author | erikj |
Tue, 12 Sep 2017 19:03:39 +0200 | |
changeset 47216 | 71c04702a3d5 |
parent 47038 | nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java@f57fa7f112a0 |
child 47262 | bbbf1b1e36e9 |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
47038
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2 |
* Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. |
16147 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.nashorn.internal.parser; |
|
27 |
||
24719 | 28 |
import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX; |
16147 | 29 |
import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; |
24719 | 30 |
import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM; |
37732 | 31 |
import static jdk.nashorn.internal.parser.TokenType.ARROW; |
16147 | 32 |
import static jdk.nashorn.internal.parser.TokenType.ASSIGN; |
33 |
import static jdk.nashorn.internal.parser.TokenType.CASE; |
|
34 |
import static jdk.nashorn.internal.parser.TokenType.CATCH; |
|
37732 | 35 |
import static jdk.nashorn.internal.parser.TokenType.CLASS; |
16147 | 36 |
import static jdk.nashorn.internal.parser.TokenType.COLON; |
37 |
import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; |
|
37732 | 38 |
import static jdk.nashorn.internal.parser.TokenType.COMMENT; |
24279 | 39 |
import static jdk.nashorn.internal.parser.TokenType.CONST; |
16147 | 40 |
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; |
41 |
import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; |
|
37732 | 42 |
import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS; |
16147 | 43 |
import static jdk.nashorn.internal.parser.TokenType.ELSE; |
44 |
import static jdk.nashorn.internal.parser.TokenType.EOF; |
|
45 |
import static jdk.nashorn.internal.parser.TokenType.EOL; |
|
37732 | 46 |
import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT; |
47 |
import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; |
|
48 |
import static jdk.nashorn.internal.parser.TokenType.EXPORT; |
|
49 |
import static jdk.nashorn.internal.parser.TokenType.EXTENDS; |
|
16147 | 50 |
import static jdk.nashorn.internal.parser.TokenType.FINALLY; |
51 |
import static jdk.nashorn.internal.parser.TokenType.FUNCTION; |
|
52 |
import static jdk.nashorn.internal.parser.TokenType.IDENT; |
|
53 |
import static jdk.nashorn.internal.parser.TokenType.IF; |
|
37732 | 54 |
import static jdk.nashorn.internal.parser.TokenType.IMPORT; |
16147 | 55 |
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; |
56 |
import static jdk.nashorn.internal.parser.TokenType.LBRACE; |
|
37732 | 57 |
import static jdk.nashorn.internal.parser.TokenType.LBRACKET; |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
58 |
import static jdk.nashorn.internal.parser.TokenType.LET; |
16147 | 59 |
import static jdk.nashorn.internal.parser.TokenType.LPAREN; |
37732 | 60 |
import static jdk.nashorn.internal.parser.TokenType.MUL; |
61 |
import static jdk.nashorn.internal.parser.TokenType.PERIOD; |
|
16147 | 62 |
import static jdk.nashorn.internal.parser.TokenType.RBRACE; |
63 |
import static jdk.nashorn.internal.parser.TokenType.RBRACKET; |
|
64 |
import static jdk.nashorn.internal.parser.TokenType.RPAREN; |
|
65 |
import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
|
37732 | 66 |
import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY; |
67 |
import static jdk.nashorn.internal.parser.TokenType.STATIC; |
|
68 |
import static jdk.nashorn.internal.parser.TokenType.STRING; |
|
69 |
import static jdk.nashorn.internal.parser.TokenType.SUPER; |
|
33414 | 70 |
import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; |
71 |
import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; |
|
72 |
import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; |
|
73 |
import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; |
|
16147 | 74 |
import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
37732 | 75 |
import static jdk.nashorn.internal.parser.TokenType.VAR; |
76 |
import static jdk.nashorn.internal.parser.TokenType.VOID; |
|
16147 | 77 |
import static jdk.nashorn.internal.parser.TokenType.WHILE; |
37732 | 78 |
import static jdk.nashorn.internal.parser.TokenType.YIELD; |
79 |
import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR; |
|
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
80 |
|
26646
332e9901f0ed
8058304: Non-serializable fields in serializable classes
hannesw
parents:
26505
diff
changeset
|
81 |
import java.io.Serializable; |
24719 | 82 |
import java.util.ArrayDeque; |
16147 | 83 |
import java.util.ArrayList; |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
84 |
import java.util.Collections; |
24719 | 85 |
import java.util.Deque; |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
86 |
import java.util.HashMap; |
16147 | 87 |
import java.util.HashSet; |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
88 |
import java.util.Iterator; |
16147 | 89 |
import java.util.List; |
90 |
import java.util.Map; |
|
37732 | 91 |
import java.util.Objects; |
92 |
import java.util.function.Consumer; |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
93 |
import jdk.nashorn.internal.codegen.CompilerConstants; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
94 |
import jdk.nashorn.internal.codegen.Namespace; |
16147 | 95 |
import jdk.nashorn.internal.ir.AccessNode; |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
96 |
import jdk.nashorn.internal.ir.BaseNode; |
16147 | 97 |
import jdk.nashorn.internal.ir.BinaryNode; |
98 |
import jdk.nashorn.internal.ir.Block; |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
99 |
import jdk.nashorn.internal.ir.BlockStatement; |
16147 | 100 |
import jdk.nashorn.internal.ir.BreakNode; |
101 |
import jdk.nashorn.internal.ir.CallNode; |
|
102 |
import jdk.nashorn.internal.ir.CaseNode; |
|
103 |
import jdk.nashorn.internal.ir.CatchNode; |
|
37732 | 104 |
import jdk.nashorn.internal.ir.ClassNode; |
16147 | 105 |
import jdk.nashorn.internal.ir.ContinueNode; |
29407 | 106 |
import jdk.nashorn.internal.ir.DebuggerNode; |
16147 | 107 |
import jdk.nashorn.internal.ir.EmptyNode; |
29407 | 108 |
import jdk.nashorn.internal.ir.ErrorNode; |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
109 |
import jdk.nashorn.internal.ir.Expression; |
37732 | 110 |
import jdk.nashorn.internal.ir.ExpressionList; |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
111 |
import jdk.nashorn.internal.ir.ExpressionStatement; |
16147 | 112 |
import jdk.nashorn.internal.ir.ForNode; |
113 |
import jdk.nashorn.internal.ir.FunctionNode; |
|
114 |
import jdk.nashorn.internal.ir.IdentNode; |
|
115 |
import jdk.nashorn.internal.ir.IfNode; |
|
116 |
import jdk.nashorn.internal.ir.IndexNode; |
|
24751 | 117 |
import jdk.nashorn.internal.ir.JoinPredecessorExpression; |
16147 | 118 |
import jdk.nashorn.internal.ir.LabelNode; |
37732 | 119 |
import jdk.nashorn.internal.ir.LexicalContext; |
16147 | 120 |
import jdk.nashorn.internal.ir.LiteralNode; |
37732 | 121 |
import jdk.nashorn.internal.ir.Module; |
16147 | 122 |
import jdk.nashorn.internal.ir.Node; |
123 |
import jdk.nashorn.internal.ir.ObjectNode; |
|
124 |
import jdk.nashorn.internal.ir.PropertyKey; |
|
125 |
import jdk.nashorn.internal.ir.PropertyNode; |
|
126 |
import jdk.nashorn.internal.ir.ReturnNode; |
|
127 |
import jdk.nashorn.internal.ir.RuntimeNode; |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
128 |
import jdk.nashorn.internal.ir.Statement; |
16147 | 129 |
import jdk.nashorn.internal.ir.SwitchNode; |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
130 |
import jdk.nashorn.internal.ir.TemplateLiteral; |
16147 | 131 |
import jdk.nashorn.internal.ir.TernaryNode; |
132 |
import jdk.nashorn.internal.ir.ThrowNode; |
|
133 |
import jdk.nashorn.internal.ir.TryNode; |
|
134 |
import jdk.nashorn.internal.ir.UnaryNode; |
|
135 |
import jdk.nashorn.internal.ir.VarNode; |
|
136 |
import jdk.nashorn.internal.ir.WhileNode; |
|
137 |
import jdk.nashorn.internal.ir.WithNode; |
|
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
138 |
import jdk.nashorn.internal.ir.debug.ASTWriter; |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
139 |
import jdk.nashorn.internal.ir.debug.PrintVisitor; |
37732 | 140 |
import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
141 |
import jdk.nashorn.internal.runtime.Context; |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
142 |
import jdk.nashorn.internal.runtime.ErrorManager; |
16147 | 143 |
import jdk.nashorn.internal.runtime.JSErrorType; |
144 |
import jdk.nashorn.internal.runtime.ParserException; |
|
24719 | 145 |
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
146 |
import jdk.nashorn.internal.runtime.ScriptEnvironment; |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
147 |
import jdk.nashorn.internal.runtime.ScriptFunctionData; |
16245
6a1c6c8bc113
8008371: Fix Dynalink compiler warnings and whitespace
attila
parents:
16239
diff
changeset
|
148 |
import jdk.nashorn.internal.runtime.ScriptingFunctions; |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
149 |
import jdk.nashorn.internal.runtime.Source; |
26246 | 150 |
import jdk.nashorn.internal.runtime.Timing; |
33533
43400f0f2b47
8141144: Move NameCodec to jdk.nashorn.internal space
attila
parents:
33414
diff
changeset
|
151 |
import jdk.nashorn.internal.runtime.linker.NameCodec; |
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
152 |
import jdk.nashorn.internal.runtime.logging.DebugLogger; |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
153 |
import jdk.nashorn.internal.runtime.logging.Loggable; |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
154 |
import jdk.nashorn.internal.runtime.logging.Logger; |
16147 | 155 |
|
156 |
/** |
|
157 |
* Builds the IR. |
|
158 |
*/ |
|
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
159 |
@Logger(name="parser") |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
160 |
public class Parser extends AbstractParser implements Loggable { |
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
161 |
private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName(); |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
162 |
private static final String CONSTRUCTOR_NAME = "constructor"; |
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
163 |
private static final String GET_NAME = "get"; |
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
164 |
private static final String SET_NAME = "set"; |
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
165 |
|
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
166 |
/** Current env. */ |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
167 |
private final ScriptEnvironment env; |
16147 | 168 |
|
16211 | 169 |
/** Is scripting mode. */ |
170 |
private final boolean scripting; |
|
171 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
172 |
private List<Statement> functionDeclarations; |
16147 | 173 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
174 |
private final ParserContext lc; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
175 |
private final Deque<Object> defaultNames; |
17233 | 176 |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
177 |
/** Namespace for function names where not explicitly given */ |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
178 |
private final Namespace namespace; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
179 |
|
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
180 |
private final DebugLogger log; |
16252
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16245
diff
changeset
|
181 |
|
18870
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
182 |
/** to receive line information from Lexer when scanning multine literals. */ |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
183 |
protected final Lexer.LineInfoReceiver lineInfoReceiver; |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
184 |
|
26503 | 185 |
private RecompilableScriptFunctionData reparsedFunction; |
24719 | 186 |
|
16147 | 187 |
/** |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
188 |
* Constructor |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
189 |
* |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
190 |
* @param env script environment |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
191 |
* @param source source to parse |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
192 |
* @param errors error manager |
16147 | 193 |
*/ |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
194 |
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) { |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
195 |
this(env, source, errors, env._strict, null); |
16147 | 196 |
} |
197 |
||
198 |
/** |
|
24719 | 199 |
* Constructor |
200 |
* |
|
201 |
* @param env script environment |
|
202 |
* @param source source to parse |
|
203 |
* @param errors error manager |
|
204 |
* @param strict strict |
|
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
205 |
* @param log debug logger if one is needed |
24719 | 206 |
*/ |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
207 |
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) { |
26503 | 208 |
this(env, source, errors, strict, 0, log); |
16147 | 209 |
} |
210 |
||
211 |
/** |
|
212 |
* Construct a parser. |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
213 |
* |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
214 |
* @param env script environment |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
215 |
* @param source source to parse |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
216 |
* @param errors error manager |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
217 |
* @param strict parser created with strict mode enabled. |
24719 | 218 |
* @param lineOffset line offset to start counting lines from |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
219 |
* @param log debug logger if one is needed |
16147 | 220 |
*/ |
26503 | 221 |
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { |
24719 | 222 |
super(source, errors, strict, lineOffset); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
223 |
this.lc = new ParserContext(); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
224 |
this.defaultNames = new ArrayDeque<>(); |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
225 |
this.env = env; |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
226 |
this.namespace = new Namespace(env.getNamespace()); |
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
227 |
this.scripting = env._scripting; |
18870
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
228 |
if (this.scripting) { |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
229 |
this.lineInfoReceiver = new Lexer.LineInfoReceiver() { |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
230 |
@Override |
19472
9476460521b3
8023017: SUB missing for widest op == number for BinaryNode
lagergren
parents:
18877
diff
changeset
|
231 |
public void lineInfo(final int receiverLine, final int receiverLinePosition) { |
18870
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
232 |
// update the parser maintained line information |
19472
9476460521b3
8023017: SUB missing for widest op == number for BinaryNode
lagergren
parents:
18877
diff
changeset
|
233 |
Parser.this.line = receiverLine; |
9476460521b3
8023017: SUB missing for widest op == number for BinaryNode
lagergren
parents:
18877
diff
changeset
|
234 |
Parser.this.linePosition = receiverLinePosition; |
18870
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
235 |
} |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
236 |
}; |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
237 |
} else { |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
238 |
// non-scripting mode script can't have multi-line literals |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
239 |
this.lineInfoReceiver = null; |
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
240 |
} |
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
241 |
|
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
242 |
this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; |
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
243 |
} |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
244 |
|
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
245 |
@Override |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
246 |
public DebugLogger getLogger() { |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
247 |
return log; |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
248 |
} |
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
249 |
|
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
250 |
@Override |
24745
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
251 |
public DebugLogger initLogger(final Context context) { |
3a6e1477362b
8041434: Add synchronization to the common global constants structure
lagergren
parents:
24744
diff
changeset
|
252 |
return context.getLogger(this.getClass()); |
16147 | 253 |
} |
254 |
||
255 |
/** |
|
24719 | 256 |
* Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can |
257 |
* preserve their already assigned name, as that name doesn't appear in their source text. |
|
258 |
* @param name the name for the first parsed function. |
|
259 |
*/ |
|
260 |
public void setFunctionName(final String name) { |
|
26243 | 261 |
defaultNames.push(createIdentNode(0, 0, name)); |
16147 | 262 |
} |
263 |
||
264 |
/** |
|
26503 | 265 |
* Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this |
266 |
* parser instance is used to reparse a previously parsed function, as part of its on-demand compilation). |
|
267 |
* This will trigger various special behaviors, such as skipping nested function bodies. |
|
268 |
* @param reparsedFunction the function being reparsed. |
|
269 |
*/ |
|
270 |
public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) { |
|
271 |
this.reparsedFunction = reparsedFunction; |
|
272 |
} |
|
273 |
||
274 |
/** |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
275 |
* Execute parse and return the resulting function node. |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
276 |
* Errors will be thrown and the error manager will contain information |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
277 |
* if parsing should fail |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
278 |
* |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
279 |
* This is the default parse call, which will name the function node |
24719 | 280 |
* {code :program} {@link CompilerConstants#PROGRAM} |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
281 |
* |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
282 |
* @return function node resulting from successful parse |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
283 |
*/ |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
284 |
public FunctionNode parse() { |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
285 |
return parse(PROGRAM.symbolName(), 0, source.getLength(), 0); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
286 |
} |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
287 |
|
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
288 |
/** |
37732 | 289 |
* Set up first token. Skips opening EOL. |
290 |
*/ |
|
291 |
private void scanFirstToken() { |
|
292 |
k = -1; |
|
293 |
next(); |
|
294 |
} |
|
295 |
||
296 |
/** |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
297 |
* Execute parse and return the resulting function node. |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
298 |
* Errors will be thrown and the error manager will contain information |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
299 |
* if parsing should fail |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
300 |
* |
24719 | 301 |
* This should be used to create one and only one function node |
302 |
* |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
303 |
* @param scriptName name for the script, given to the parsed FunctionNode |
24719 | 304 |
* @param startPos start position in source |
305 |
* @param len length of parse |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
306 |
* @param reparseFlags flags provided by {@link RecompilableScriptFunctionData} as context for |
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
307 |
* the code being reparsed. This allows us to recognize special forms of functions such |
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
308 |
* as property getters and setters or instances of ES6 method shorthand in object literals. |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
309 |
* |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
310 |
* @return function node resulting from successful parse |
16147 | 311 |
*/ |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
312 |
public FunctionNode parse(final String scriptName, final int startPos, final int len, final int reparseFlags) { |
24764
722a9603b237
8043633: In order to remove global state outside of contexts, make sure Timing class is an instance and not a static global collection of data. Move into Context. Move -Dnashorn.timing to an official logging option.
lagergren
parents:
24759
diff
changeset
|
313 |
final boolean isTimingEnabled = env.isTimingEnabled(); |
26246 | 314 |
final long t0 = isTimingEnabled ? System.nanoTime() : 0L; |
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
315 |
log.info(this, " begin for '", scriptName, "'"); |
16252
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16245
diff
changeset
|
316 |
|
16147 | 317 |
try { |
318 |
stream = new TokenStream(); |
|
32444 | 319 |
lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); |
24719 | 320 |
lexer.line = lexer.pendingLine = lineOffset + 1; |
321 |
line = lineOffset; |
|
16147 | 322 |
|
37732 | 323 |
scanFirstToken(); |
16147 | 324 |
// Begin parse. |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
325 |
return program(scriptName, reparseFlags); |
16147 | 326 |
} catch (final Exception e) { |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
327 |
handleParseException(e); |
16147 | 328 |
|
329 |
return null; |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
330 |
} finally { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
331 |
final String end = this + " end '" + scriptName + "'"; |
24764
722a9603b237
8043633: In order to remove global state outside of contexts, make sure Timing class is an instance and not a static global collection of data. Move into Context. Move -Dnashorn.timing to an official logging option.
lagergren
parents:
24759
diff
changeset
|
332 |
if (isTimingEnabled) { |
26246 | 333 |
env._timing.accumulateTime(toString(), System.nanoTime() - t0); |
334 |
log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms"); |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
335 |
} else { |
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
336 |
log.info(end); |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
337 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
338 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
339 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
340 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
341 |
/** |
37732 | 342 |
* Parse and return the resulting module. |
343 |
* Errors will be thrown and the error manager will contain information |
|
344 |
* if parsing should fail |
|
345 |
* |
|
346 |
* @param moduleName name for the module, given to the parsed FunctionNode |
|
347 |
* @param startPos start position in source |
|
348 |
* @param len length of parse |
|
349 |
* |
|
350 |
* @return function node resulting from successful parse |
|
351 |
*/ |
|
352 |
public FunctionNode parseModule(final String moduleName, final int startPos, final int len) { |
|
353 |
try { |
|
354 |
stream = new TokenStream(); |
|
355 |
lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); |
|
356 |
lexer.line = lexer.pendingLine = lineOffset + 1; |
|
357 |
line = lineOffset; |
|
358 |
||
359 |
scanFirstToken(); |
|
360 |
// Begin parse. |
|
361 |
return module(moduleName); |
|
362 |
} catch (final Exception e) { |
|
363 |
handleParseException(e); |
|
364 |
||
365 |
return null; |
|
366 |
} |
|
367 |
} |
|
368 |
||
369 |
/** |
|
370 |
* Entry point for parsing a module. |
|
371 |
* |
|
372 |
* @param moduleName the module name |
|
373 |
* @return the parsed module |
|
374 |
*/ |
|
375 |
public FunctionNode parseModule(final String moduleName) { |
|
376 |
return parseModule(moduleName, 0, source.getLength()); |
|
377 |
} |
|
378 |
||
379 |
/** |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
380 |
* Parse and return the list of function parameter list. A comma |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
381 |
* separated list of function parameter identifiers is expected to be parsed. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
382 |
* Errors will be thrown and the error manager will contain information |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
383 |
* if parsing should fail. This method is used to check if parameter Strings |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
384 |
* passed to "Function" constructor is a valid or not. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
385 |
* |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
386 |
* @return the list of IdentNodes representing the formal parameter list |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
387 |
*/ |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
388 |
public List<IdentNode> parseFormalParameterList() { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
389 |
try { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
390 |
stream = new TokenStream(); |
32444 | 391 |
lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
392 |
|
37732 | 393 |
scanFirstToken(); |
394 |
||
395 |
return formalParameterList(TokenType.EOF, false); |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
396 |
} catch (final Exception e) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
397 |
handleParseException(e); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
398 |
return null; |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
399 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
400 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
401 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
402 |
/** |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
403 |
* Execute parse and return the resulting function node. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
404 |
* Errors will be thrown and the error manager will contain information |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
405 |
* if parsing should fail. This method is used to check if code String |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
406 |
* passed to "Function" constructor is a valid function body or not. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
407 |
* |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
408 |
* @return function node resulting from successful parse |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
409 |
*/ |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
410 |
public FunctionNode parseFunctionBody() { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
411 |
try { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
412 |
stream = new TokenStream(); |
32444 | 413 |
lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); |
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24719
diff
changeset
|
414 |
final int functionLine = line; |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
415 |
|
37732 | 416 |
scanFirstToken(); |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
417 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
418 |
// Make a fake token for the function. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
419 |
final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
420 |
// Set up the function to append elements. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
421 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
422 |
final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
423 |
final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList()); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
424 |
lc.push(function); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
425 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
426 |
final ParserContextBlockNode body = newBlock(); |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
427 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
428 |
functionDeclarations = new ArrayList<>(); |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
429 |
sourceElements(0); |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
430 |
addFunctionDeclarations(function); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
431 |
functionDeclarations = null; |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
432 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
433 |
restoreBlock(body); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
434 |
body.setFlag(Block.NEEDS_SCOPE); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
435 |
|
29407 | 436 |
final Block functionBody = new Block(functionToken, source.getLength() - 1, |
437 |
body.getFlags() | Block.IS_SYNTHETIC, body.getStatements()); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
438 |
lc.pop(function); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
439 |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
440 |
expect(EOF); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
441 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
442 |
final FunctionNode functionNode = createFunctionNode( |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
443 |
function, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
444 |
functionToken, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
445 |
ident, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
446 |
Collections.<IdentNode>emptyList(), |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
447 |
FunctionNode.Kind.NORMAL, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
448 |
functionLine, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
449 |
functionBody); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
450 |
printAST(functionNode); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
451 |
return functionNode; |
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
452 |
} catch (final Exception e) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
453 |
handleParseException(e); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
454 |
return null; |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
455 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
456 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
457 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
458 |
private void handleParseException(final Exception e) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
459 |
// Extract message from exception. The message will be in error |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
460 |
// message format. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
461 |
String message = e.getMessage(); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
462 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
463 |
// If empty message. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
464 |
if (message == null) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
465 |
message = e.toString(); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
466 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
467 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
468 |
// Issue message. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
469 |
if (e instanceof ParserException) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
470 |
errors.error((ParserException)e); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
471 |
} else { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
472 |
errors.error(message); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
473 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
474 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
475 |
if (env._dump_on_error) { |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
476 |
e.printStackTrace(env.getErr()); |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
477 |
} |
16147 | 478 |
} |
479 |
||
480 |
/** |
|
481 |
* Skip to a good parsing recovery point. |
|
482 |
*/ |
|
483 |
private void recover(final Exception e) { |
|
484 |
if (e != null) { |
|
485 |
// Extract message from exception. The message will be in error |
|
486 |
// message format. |
|
487 |
String message = e.getMessage(); |
|
488 |
||
489 |
// If empty message. |
|
490 |
if (message == null) { |
|
491 |
message = e.toString(); |
|
492 |
} |
|
493 |
||
494 |
// Issue message. |
|
495 |
if (e instanceof ParserException) { |
|
496 |
errors.error((ParserException)e); |
|
497 |
} else { |
|
498 |
errors.error(message); |
|
499 |
} |
|
500 |
||
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
501 |
if (env._dump_on_error) { |
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
502 |
e.printStackTrace(env.getErr()); |
16147 | 503 |
} |
504 |
} |
|
505 |
||
506 |
// Skip to a recovery point. |
|
37732 | 507 |
loop: |
16147 | 508 |
while (true) { |
509 |
switch (type) { |
|
510 |
case EOF: |
|
511 |
// Can not go any further. |
|
512 |
break loop; |
|
513 |
case EOL: |
|
514 |
case SEMICOLON: |
|
515 |
case RBRACE: |
|
516 |
// Good recovery points. |
|
517 |
next(); |
|
518 |
break loop; |
|
519 |
default: |
|
520 |
// So we can recover after EOL. |
|
521 |
nextOrEOL(); |
|
522 |
break; |
|
523 |
} |
|
524 |
} |
|
525 |
} |
|
526 |
||
527 |
/** |
|
528 |
* Set up a new block. |
|
529 |
* |
|
530 |
* @return New block. |
|
531 |
*/ |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
532 |
private ParserContextBlockNode newBlock() { |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
533 |
return lc.push(new ParserContextBlockNode(token)); |
16147 | 534 |
} |
535 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
536 |
private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) { |
16147 | 537 |
// Build function name. |
538 |
final StringBuilder sb = new StringBuilder(); |
|
539 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
540 |
final ParserContextFunctionNode parentFunction = lc.getCurrentFunction(); |
17233 | 541 |
if (parentFunction != null && !parentFunction.isProgram()) { |
37923
be223c7da1b8
8156896: Script stack trace should display function names
hannesw
parents:
37835
diff
changeset
|
542 |
sb.append(parentFunction.getName()).append(CompilerConstants.NESTED_FUNCTION_SEPARATOR.symbolName()); |
16147 | 543 |
} |
544 |
||
22374
5231ab59e740
8030809: Anonymous functions should not be shown with internal names in script stack trace
sundar
parents:
21868
diff
changeset
|
545 |
assert ident.getName() != null; |
5231ab59e740
8030809: Anonymous functions should not be shown with internal names in script stack trace
sundar
parents:
21868
diff
changeset
|
546 |
sb.append(ident.getName()); |
5231ab59e740
8030809: Anonymous functions should not be shown with internal names in script stack trace
sundar
parents:
21868
diff
changeset
|
547 |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16211
diff
changeset
|
548 |
final String name = namespace.uniqueName(sb.toString()); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
549 |
assert parentFunction != null || kind == FunctionNode.Kind.MODULE || name.equals(PROGRAM.symbolName()) : "name = " + name; |
17233 | 550 |
|
551 |
int flags = 0; |
|
552 |
if (isStrictMode) { |
|
553 |
flags |= FunctionNode.IS_STRICT; |
|
554 |
} |
|
24719 | 555 |
if (parentFunction == null) { |
556 |
flags |= FunctionNode.IS_PROGRAM; |
|
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17257
diff
changeset
|
557 |
} |
16147 | 558 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
559 |
final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
560 |
functionNode.setFlag(flags); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
561 |
return functionNode; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
562 |
} |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
563 |
|
37732 | 564 |
private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) { |
565 |
// assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody(); |
|
16147 | 566 |
// Start new block. |
24719 | 567 |
final FunctionNode functionNode = |
17233 | 568 |
new FunctionNode( |
569 |
source, |
|
24719 | 570 |
functionLine, |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
571 |
body.getToken(), |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
572 |
Token.descPosition(body.getToken()), |
17233 | 573 |
startToken, |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
574 |
function.getLastToken(), |
17233 | 575 |
namespace, |
576 |
ident, |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
577 |
function.getName(), |
17233 | 578 |
parameters, |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
579 |
function.getParameterExpressions(), |
17233 | 580 |
kind, |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
581 |
function.getFlags(), |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
582 |
body, |
37732 | 583 |
function.getEndParserState(), |
584 |
function.getModule(), |
|
585 |
function.getDebugFlags()); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
586 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
587 |
printAST(functionNode); |
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17257
diff
changeset
|
588 |
|
17233 | 589 |
return functionNode; |
16147 | 590 |
} |
591 |
||
592 |
/** |
|
593 |
* Restore the current block. |
|
594 |
*/ |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
595 |
private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) { |
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17257
diff
changeset
|
596 |
return lc.pop(block); |
17233 | 597 |
} |
598 |
||
16147 | 599 |
/** |
600 |
* Get the statements in a block. |
|
601 |
* @return Block statements. |
|
602 |
*/ |
|
603 |
private Block getBlock(final boolean needsBraces) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
604 |
final long blockToken = token; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
605 |
final ParserContextBlockNode newBlock = newBlock(); |
16147 | 606 |
try { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
607 |
// Block opening brace. |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
608 |
if (needsBraces) { |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
609 |
expect(LBRACE); |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
610 |
} |
17233 | 611 |
// Accumulate block statements. |
612 |
statementList(); |
|
613 |
||
16147 | 614 |
} finally { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
615 |
restoreBlock(newBlock); |
16147 | 616 |
} |
617 |
||
618 |
// Block closing brace. |
|
619 |
if (needsBraces) { |
|
620 |
expect(RBRACE); |
|
621 |
} |
|
622 |
||
37732 | 623 |
final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC); |
29407 | 624 |
return new Block(blockToken, finish, flags, newBlock.getStatements()); |
16147 | 625 |
} |
626 |
||
37732 | 627 |
/** |
16147 | 628 |
* Get all the statements generated by a single statement. |
629 |
* @return Statements. |
|
630 |
*/ |
|
631 |
private Block getStatement() { |
|
37732 | 632 |
return getStatement(false); |
633 |
} |
|
634 |
||
41422 | 635 |
private Block getStatement(final boolean labelledStatement) { |
16147 | 636 |
if (type == LBRACE) { |
637 |
return getBlock(true); |
|
638 |
} |
|
639 |
// Set up new block. Captures first token. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
640 |
final ParserContextBlockNode newBlock = newBlock(); |
16147 | 641 |
try { |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
642 |
statement(false, 0, true, labelledStatement); |
16147 | 643 |
} finally { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
644 |
restoreBlock(newBlock); |
16147 | 645 |
} |
29407 | 646 |
return new Block(newBlock.getToken(), finish, newBlock.getFlags() | Block.IS_SYNTHETIC, newBlock.getStatements()); |
16147 | 647 |
} |
648 |
||
649 |
/** |
|
650 |
* Detect calls to special functions. |
|
651 |
* @param ident Called function. |
|
652 |
*/ |
|
653 |
private void detectSpecialFunction(final IdentNode ident) { |
|
654 |
final String name = ident.getName(); |
|
655 |
||
17233 | 656 |
if (EVAL.symbolName().equals(name)) { |
17255 | 657 |
markEval(lc); |
37732 | 658 |
} else if (SUPER.getName().equals(name)) { |
659 |
assert ident.isDirectSuper(); |
|
660 |
markSuperCall(lc); |
|
16147 | 661 |
} |
662 |
} |
|
663 |
||
664 |
/** |
|
665 |
* Detect use of special properties. |
|
666 |
* @param ident Referenced property. |
|
667 |
*/ |
|
668 |
private void detectSpecialProperty(final IdentNode ident) { |
|
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
669 |
if (isArguments(ident)) { |
37732 | 670 |
// skip over arrow functions, e.g. function f() { return (() => arguments.length)(); } |
671 |
getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS); |
|
16147 | 672 |
} |
673 |
} |
|
674 |
||
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
675 |
private boolean useBlockScope() { |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
676 |
return env._es6; |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
677 |
} |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
678 |
|
37732 | 679 |
private boolean isES6() { |
680 |
return env._es6; |
|
681 |
} |
|
682 |
||
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
683 |
private static boolean isArguments(final String name) { |
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
684 |
return ARGUMENTS_NAME.equals(name); |
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
685 |
} |
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
686 |
|
37732 | 687 |
static boolean isArguments(final IdentNode ident) { |
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
688 |
return isArguments(ident.getName()); |
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
689 |
} |
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
690 |
|
16147 | 691 |
/** |
692 |
* Tells whether a IdentNode can be used as L-value of an assignment |
|
693 |
* |
|
694 |
* @param ident IdentNode to be checked |
|
695 |
* @return whether the ident can be used as L-value |
|
696 |
*/ |
|
697 |
private static boolean checkIdentLValue(final IdentNode ident) { |
|
30392
dc4a419b2982
8079362: Enforce best practices for Node token API usage
attila
parents:
29539
diff
changeset
|
698 |
return ident.tokenType().getKind() != TokenKind.KEYWORD; |
16147 | 699 |
} |
700 |
||
701 |
/** |
|
702 |
* Verify an assignment expression. |
|
703 |
* @param op Operation token. |
|
704 |
* @param lhs Left hand side expression. |
|
705 |
* @param rhs Right hand side expression. |
|
706 |
* @return Verified expression. |
|
707 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
708 |
private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) { |
16147 | 709 |
final TokenType opType = Token.descType(op); |
710 |
||
711 |
switch (opType) { |
|
712 |
case ASSIGN: |
|
713 |
case ASSIGN_ADD: |
|
714 |
case ASSIGN_BIT_AND: |
|
715 |
case ASSIGN_BIT_OR: |
|
716 |
case ASSIGN_BIT_XOR: |
|
717 |
case ASSIGN_DIV: |
|
718 |
case ASSIGN_MOD: |
|
719 |
case ASSIGN_MUL: |
|
720 |
case ASSIGN_SAR: |
|
721 |
case ASSIGN_SHL: |
|
722 |
case ASSIGN_SHR: |
|
723 |
case ASSIGN_SUB: |
|
724 |
if (lhs instanceof IdentNode) { |
|
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
725 |
if (!checkIdentLValue((IdentNode)lhs)) { |
18632
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
726 |
return referenceError(lhs, rhs, false); |
16147 | 727 |
} |
37732 | 728 |
verifyIdent((IdentNode)lhs, "assignment"); |
729 |
break; |
|
730 |
} else if (lhs instanceof AccessNode || lhs instanceof IndexNode) { |
|
731 |
break; |
|
732 |
} else if (opType == ASSIGN && isDestructuringLhs(lhs)) { |
|
733 |
verifyDestructuringAssignmentPattern(lhs, "assignment"); |
|
734 |
break; |
|
735 |
} else { |
|
736 |
return referenceError(lhs, rhs, env._early_lvalue_error); |
|
16147 | 737 |
} |
738 |
default: |
|
739 |
break; |
|
740 |
} |
|
741 |
||
742 |
// Build up node. |
|
24751 | 743 |
if(BinaryNode.isLogical(opType)) { |
744 |
return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); |
|
745 |
} |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
746 |
return new BinaryNode(op, lhs, rhs); |
16147 | 747 |
} |
748 |
||
41422 | 749 |
private boolean isDestructuringLhs(final Expression lhs) { |
37732 | 750 |
if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) { |
751 |
return isES6(); |
|
752 |
} |
|
753 |
return false; |
|
754 |
} |
|
755 |
||
41422 | 756 |
private void verifyDestructuringAssignmentPattern(final Expression pattern, final String contextString) { |
37732 | 757 |
assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; |
41425 | 758 |
pattern.accept(new VerifyDestructuringPatternNodeVisitor(new LexicalContext()) { |
37732 | 759 |
@Override |
41425 | 760 |
protected void verifySpreadElement(final Expression lvalue) { |
761 |
if (!checkValidLValue(lvalue, contextString)) { |
|
762 |
throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken()); |
|
37732 | 763 |
} |
764 |
} |
|
765 |
||
766 |
@Override |
|
41422 | 767 |
public boolean enterIdentNode(final IdentNode identNode) { |
37732 | 768 |
verifyIdent(identNode, contextString); |
769 |
if (!checkIdentLValue(identNode)) { |
|
770 |
referenceError(identNode, null, true); |
|
771 |
return false; |
|
772 |
} |
|
773 |
return false; |
|
774 |
} |
|
775 |
||
776 |
@Override |
|
41422 | 777 |
public boolean enterAccessNode(final AccessNode accessNode) { |
37732 | 778 |
return false; |
779 |
} |
|
780 |
||
781 |
@Override |
|
41422 | 782 |
public boolean enterIndexNode(final IndexNode indexNode) { |
37732 | 783 |
return false; |
784 |
} |
|
785 |
||
786 |
@Override |
|
41422 | 787 |
protected boolean enterDefault(final Node node) { |
37732 | 788 |
throw error(String.format("unexpected node in AssignmentPattern: %s", node)); |
789 |
} |
|
790 |
}); |
|
791 |
} |
|
792 |
||
16147 | 793 |
/** |
794 |
* Reduce increment/decrement to simpler operations. |
|
795 |
* @param firstToken First token. |
|
796 |
* @param tokenType Operation token (INCPREFIX/DEC.) |
|
797 |
* @param expression Left hand side expression. |
|
798 |
* @param isPostfix Prefix or postfix. |
|
799 |
* @return Reduced expression. |
|
800 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
801 |
private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) { |
16147 | 802 |
if (isPostfix) { |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
803 |
return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); |
16147 | 804 |
} |
805 |
||
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
806 |
return new UnaryNode(firstToken, expression); |
16147 | 807 |
} |
808 |
||
809 |
/** |
|
810 |
* ----------------------------------------------------------------------- |
|
811 |
* |
|
812 |
* Grammar based on |
|
813 |
* |
|
814 |
* ECMAScript Language Specification |
|
815 |
* ECMA-262 5th Edition / December 2009 |
|
816 |
* |
|
817 |
* ----------------------------------------------------------------------- |
|
818 |
*/ |
|
819 |
||
820 |
/** |
|
821 |
* Program : |
|
822 |
* SourceElements? |
|
823 |
* |
|
824 |
* See 14 |
|
825 |
* |
|
826 |
* Parse the top level script. |
|
827 |
*/ |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
828 |
private FunctionNode program(final String scriptName, final int reparseFlags) { |
24719 | 829 |
// Make a pseudo-token for the script holding its start and length. |
24994
92a19723a5ac
8047035: (function() "hello")() crashes in Lexer with jdk9
sundar
parents:
24769
diff
changeset
|
830 |
final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength()); |
24719 | 831 |
final int functionLine = line; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
832 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
833 |
final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
834 |
final ParserContextFunctionNode script = createParserContextFunctionNode( |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
835 |
ident, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
836 |
functionToken, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
837 |
FunctionNode.Kind.SCRIPT, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
838 |
functionLine, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
839 |
Collections.<IdentNode>emptyList()); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
840 |
lc.push(script); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
841 |
final ParserContextBlockNode body = newBlock(); |
27814
96427359f4fe
8057691: Nashorn: let & const declarations are not shared between scripts
hannesw
parents:
27102
diff
changeset
|
842 |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
843 |
functionDeclarations = new ArrayList<>(); |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
844 |
sourceElements(reparseFlags); |
27814
96427359f4fe
8057691: Nashorn: let & const declarations are not shared between scripts
hannesw
parents:
27102
diff
changeset
|
845 |
addFunctionDeclarations(script); |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
846 |
functionDeclarations = null; |
27814
96427359f4fe
8057691: Nashorn: let & const declarations are not shared between scripts
hannesw
parents:
27102
diff
changeset
|
847 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
848 |
restoreBlock(body); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
849 |
body.setFlag(Block.NEEDS_SCOPE); |
37732 | 850 |
final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
851 |
lc.pop(script); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
852 |
script.setLastToken(token); |
17233 | 853 |
|
16147 | 854 |
expect(EOF); |
17233 | 855 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
856 |
return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody); |
16147 | 857 |
} |
858 |
||
859 |
/** |
|
860 |
* Directive value or null if statement is not a directive. |
|
861 |
* |
|
862 |
* @param stmt Statement to be checked |
|
863 |
* @return Directive value if the given statement is a directive |
|
864 |
*/ |
|
865 |
private String getDirective(final Node stmt) { |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
866 |
if (stmt instanceof ExpressionStatement) { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
867 |
final Node expr = ((ExpressionStatement)stmt).getExpression(); |
16147 | 868 |
if (expr instanceof LiteralNode) { |
869 |
final LiteralNode<?> lit = (LiteralNode<?>)expr; |
|
870 |
final long litToken = lit.getToken(); |
|
871 |
final TokenType tt = Token.descType(litToken); |
|
872 |
// A directive is either a string or an escape string |
|
873 |
if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) { |
|
874 |
// Make sure that we don't unescape anything. Return as seen in source! |
|
875 |
return source.getString(lit.getStart(), Token.descLength(litToken)); |
|
876 |
} |
|
877 |
} |
|
878 |
} |
|
879 |
||
880 |
return null; |
|
881 |
} |
|
882 |
||
883 |
/** |
|
884 |
* SourceElements : |
|
885 |
* SourceElement |
|
886 |
* SourceElements SourceElement |
|
887 |
* |
|
888 |
* See 14 |
|
889 |
* |
|
890 |
* Parse the elements of the script or function. |
|
891 |
*/ |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
892 |
private void sourceElements(final int reparseFlags) { |
24719 | 893 |
List<Node> directiveStmts = null; |
894 |
boolean checkDirective = true; |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
895 |
int functionFlags = reparseFlags; |
24719 | 896 |
final boolean oldStrictMode = isStrictMode; |
897 |
||
16147 | 898 |
|
899 |
try { |
|
900 |
// If is a script, then process until the end of the script. |
|
901 |
while (type != EOF) { |
|
902 |
// Break if the end of a code block. |
|
903 |
if (type == RBRACE) { |
|
904 |
break; |
|
905 |
} |
|
906 |
||
907 |
try { |
|
908 |
// Get the next element. |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
909 |
statement(true, functionFlags, false, false); |
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
910 |
functionFlags = 0; |
16147 | 911 |
|
912 |
// check for directive prologues |
|
913 |
if (checkDirective) { |
|
914 |
// skip any debug statement like line number to get actual first line |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
915 |
final Statement lastStatement = lc.getLastStatement(); |
16147 | 916 |
|
917 |
// get directive prologue, if any |
|
918 |
final String directive = getDirective(lastStatement); |
|
919 |
||
920 |
// If we have seen first non-directive statement, |
|
921 |
// no more directive statements!! |
|
922 |
checkDirective = directive != null; |
|
923 |
||
924 |
if (checkDirective) { |
|
925 |
if (!oldStrictMode) { |
|
926 |
if (directiveStmts == null) { |
|
927 |
directiveStmts = new ArrayList<>(); |
|
928 |
} |
|
929 |
directiveStmts.add(lastStatement); |
|
930 |
} |
|
931 |
||
932 |
// handle use strict directive |
|
933 |
if ("use strict".equals(directive)) { |
|
934 |
isStrictMode = true; |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
935 |
final ParserContextFunctionNode function = lc.getCurrentFunction(); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
936 |
function.setFlag(FunctionNode.IS_STRICT); |
16147 | 937 |
|
938 |
// We don't need to check these, if lexical environment is already strict |
|
939 |
if (!oldStrictMode && directiveStmts != null) { |
|
940 |
// check that directives preceding this one do not violate strictness |
|
941 |
for (final Node statement : directiveStmts) { |
|
32534
b3ec7f3b3c2a
8136349: Typos patch for nashorn sources submitted on Sep 10, 2015
sundar
parents:
32444
diff
changeset
|
942 |
// the get value will force unescape of preceding |
16147 | 943 |
// escaped string directives |
944 |
getValue(statement.getToken()); |
|
945 |
} |
|
946 |
||
947 |
// verify that function name as well as parameter names |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16196
diff
changeset
|
948 |
// satisfy strict mode restrictions. |
37732 | 949 |
verifyIdent(function.getIdent(), "function name"); |
16147 | 950 |
for (final IdentNode param : function.getParameters()) { |
37732 | 951 |
verifyIdent(param, "function parameter"); |
16147 | 952 |
} |
953 |
} |
|
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
954 |
} else if (Context.DEBUG) { |
37732 | 955 |
final int debugFlag = FunctionNode.getDirectiveFlag(directive); |
956 |
if (debugFlag != 0) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
957 |
final ParserContextFunctionNode function = lc.getCurrentFunction(); |
37732 | 958 |
function.setDebugFlag(debugFlag); |
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
959 |
} |
16147 | 960 |
} |
961 |
} |
|
962 |
} |
|
963 |
} catch (final Exception e) { |
|
29407 | 964 |
final int errorLine = line; |
965 |
final long errorToken = token; |
|
17233 | 966 |
//recover parsing |
16147 | 967 |
recover(e); |
29407 | 968 |
final ErrorNode errorExpr = new ErrorNode(errorToken, finish); |
969 |
final ExpressionStatement expressionStatement = new ExpressionStatement(errorLine, errorToken, finish, errorExpr); |
|
970 |
appendStatement(expressionStatement); |
|
16147 | 971 |
} |
972 |
||
973 |
// No backtracking from here on. |
|
974 |
stream.commit(k); |
|
975 |
} |
|
976 |
} finally { |
|
977 |
isStrictMode = oldStrictMode; |
|
978 |
} |
|
979 |
} |
|
980 |
||
981 |
/** |
|
37732 | 982 |
* Parse any of the basic statement types. |
983 |
* |
|
16147 | 984 |
* Statement : |
37732 | 985 |
* BlockStatement |
16147 | 986 |
* VariableStatement |
987 |
* EmptyStatement |
|
988 |
* ExpressionStatement |
|
989 |
* IfStatement |
|
37732 | 990 |
* BreakableStatement |
16147 | 991 |
* ContinueStatement |
992 |
* BreakStatement |
|
993 |
* ReturnStatement |
|
994 |
* WithStatement |
|
995 |
* LabelledStatement |
|
996 |
* ThrowStatement |
|
997 |
* TryStatement |
|
998 |
* DebuggerStatement |
|
999 |
* |
|
37732 | 1000 |
* BreakableStatement : |
1001 |
* IterationStatement |
|
1002 |
* SwitchStatement |
|
1003 |
* |
|
1004 |
* BlockStatement : |
|
1005 |
* Block |
|
1006 |
* |
|
1007 |
* Block : |
|
1008 |
* { StatementList opt } |
|
16147 | 1009 |
* |
37732 | 1010 |
* StatementList : |
1011 |
* StatementListItem |
|
1012 |
* StatementList StatementListItem |
|
1013 |
* |
|
1014 |
* StatementItem : |
|
1015 |
* Statement |
|
1016 |
* Declaration |
|
1017 |
* |
|
1018 |
* Declaration : |
|
1019 |
* HoistableDeclaration |
|
1020 |
* ClassDeclaration |
|
1021 |
* LexicalDeclaration |
|
1022 |
* |
|
1023 |
* HoistableDeclaration : |
|
1024 |
* FunctionDeclaration |
|
1025 |
* GeneratorDeclaration |
|
16147 | 1026 |
*/ |
1027 |
private void statement() { |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1028 |
statement(false, 0, false, false); |
16147 | 1029 |
} |
1030 |
||
1031 |
/** |
|
1032 |
* @param topLevel does this statement occur at the "top level" of a script or a function? |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1033 |
* @param reparseFlags reparse flags to decide whether to allow property "get" and "set" functions or ES6 methods. |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1034 |
* @param singleStatement are we in a single statement context? |
16147 | 1035 |
*/ |
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1036 |
private void statement(final boolean topLevel, final int reparseFlags, final boolean singleStatement, final boolean labelledStatement) { |
16147 | 1037 |
switch (type) { |
1038 |
case LBRACE: |
|
1039 |
block(); |
|
1040 |
break; |
|
1041 |
case VAR: |
|
36696 | 1042 |
variableStatement(type); |
16147 | 1043 |
break; |
1044 |
case SEMICOLON: |
|
1045 |
emptyStatement(); |
|
1046 |
break; |
|
1047 |
case IF: |
|
1048 |
ifStatement(); |
|
1049 |
break; |
|
1050 |
case FOR: |
|
1051 |
forStatement(); |
|
1052 |
break; |
|
1053 |
case WHILE: |
|
1054 |
whileStatement(); |
|
1055 |
break; |
|
1056 |
case DO: |
|
1057 |
doStatement(); |
|
1058 |
break; |
|
1059 |
case CONTINUE: |
|
1060 |
continueStatement(); |
|
1061 |
break; |
|
1062 |
case BREAK: |
|
1063 |
breakStatement(); |
|
1064 |
break; |
|
1065 |
case RETURN: |
|
1066 |
returnStatement(); |
|
1067 |
break; |
|
1068 |
case WITH: |
|
1069 |
withStatement(); |
|
1070 |
break; |
|
1071 |
case SWITCH: |
|
1072 |
switchStatement(); |
|
1073 |
break; |
|
1074 |
case THROW: |
|
1075 |
throwStatement(); |
|
1076 |
break; |
|
1077 |
case TRY: |
|
1078 |
tryStatement(); |
|
1079 |
break; |
|
1080 |
case DEBUGGER: |
|
1081 |
debuggerStatement(); |
|
1082 |
break; |
|
1083 |
case RPAREN: |
|
1084 |
case RBRACKET: |
|
1085 |
case EOF: |
|
1086 |
expect(SEMICOLON); |
|
1087 |
break; |
|
37732 | 1088 |
case FUNCTION: |
1089 |
// As per spec (ECMA section 12), function declarations as arbitrary statement |
|
1090 |
// is not "portable". Implementation can issue a warning or disallow the same. |
|
1091 |
if (singleStatement) { |
|
1092 |
// ES6 B.3.2 Labelled Function Declarations |
|
1093 |
// It is a Syntax Error if any strict mode source code matches this rule: |
|
1094 |
// LabelledItem : FunctionDeclaration. |
|
1095 |
if (!labelledStatement || isStrictMode) { |
|
1096 |
throw error(AbstractParser.message("expected.stmt", "function declaration"), token); |
|
1097 |
} |
|
1098 |
} |
|
1099 |
functionExpression(true, topLevel || labelledStatement); |
|
1100 |
return; |
|
16147 | 1101 |
default: |
37732 | 1102 |
if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) { |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1103 |
if (singleStatement) { |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1104 |
throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1105 |
} |
36696 | 1106 |
variableStatement(type); |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1107 |
break; |
37732 | 1108 |
} else if (type == CLASS && isES6()) { |
1109 |
if (singleStatement) { |
|
1110 |
throw error(AbstractParser.message("expected.stmt", "class declaration"), token); |
|
1111 |
} |
|
1112 |
classDeclaration(false); |
|
1113 |
break; |
|
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1114 |
} |
24279 | 1115 |
if (env._const_as_var && type == CONST) { |
36696 | 1116 |
variableStatement(TokenType.VAR); |
24279 | 1117 |
break; |
1118 |
} |
|
1119 |
||
16147 | 1120 |
if (type == IDENT || isNonStrictModeIdent()) { |
1121 |
if (T(k + 1) == COLON) { |
|
1122 |
labelStatement(); |
|
1123 |
return; |
|
1124 |
} |
|
41145
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1125 |
|
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1126 |
if ((reparseFlags & ScriptFunctionData.IS_PROPERTY_ACCESSOR) != 0) { |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1127 |
final String ident = (String) getValue(); |
24719 | 1128 |
final long propertyToken = token; |
1129 |
final int propertyLine = line; |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1130 |
if (GET_NAME.equals(ident)) { |
24719 | 1131 |
next(); |
1132 |
addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); |
|
1133 |
return; |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1134 |
} else if (SET_NAME.equals(ident)) { |
24719 | 1135 |
next(); |
1136 |
addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); |
|
1137 |
return; |
|
1138 |
} |
|
1139 |
} |
|
16147 | 1140 |
} |
1141 |
||
41145
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1142 |
if ((reparseFlags & ScriptFunctionData.IS_ES6_METHOD) != 0 |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1143 |
&& (type == IDENT || type == LBRACKET || isNonStrictModeIdent())) { |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1144 |
final String ident = (String)getValue(); |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1145 |
final long propertyToken = token; |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1146 |
final int propertyLine = line; |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1147 |
final Expression propertyKey = propertyName(); |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1148 |
|
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1149 |
// Code below will need refinement once we fully support ES6 class syntax |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1150 |
final int flags = CONSTRUCTOR_NAME.equals(ident) ? FunctionNode.ES6_IS_CLASS_CONSTRUCTOR : FunctionNode.ES6_IS_METHOD; |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1151 |
addPropertyFunctionStatement(propertyMethodFunction(propertyKey, propertyToken, propertyLine, false, flags, false)); |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1152 |
return; |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1153 |
} |
b9a1cb9ed1d3
8164467: ES6 computed properties are implemented wrongly
hannesw
parents:
39662
diff
changeset
|
1154 |
|
16147 | 1155 |
expressionStatement(); |
1156 |
break; |
|
1157 |
} |
|
1158 |
} |
|
1159 |
||
24719 | 1160 |
private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { |
1161 |
final FunctionNode fn = propertyFunction.functionNode; |
|
1162 |
functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); |
|
1163 |
} |
|
1164 |
||
16147 | 1165 |
/** |
37732 | 1166 |
* ClassDeclaration[Yield, Default] : |
1167 |
* class BindingIdentifier[?Yield] ClassTail[?Yield] |
|
1168 |
* [+Default] class ClassTail[?Yield] |
|
1169 |
*/ |
|
41422 | 1170 |
private ClassNode classDeclaration(final boolean isDefault) { |
1171 |
final int classLineNumber = line; |
|
1172 |
||
1173 |
final ClassNode classExpression = classExpression(!isDefault); |
|
37732 | 1174 |
|
1175 |
if (!isDefault) { |
|
41422 | 1176 |
final VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST); |
37732 | 1177 |
appendStatement(classVar); |
1178 |
} |
|
1179 |
return classExpression; |
|
1180 |
} |
|
1181 |
||
1182 |
/** |
|
1183 |
* ClassExpression[Yield] : |
|
1184 |
* class BindingIdentifier[?Yield]opt ClassTail[?Yield] |
|
1185 |
*/ |
|
41422 | 1186 |
private ClassNode classExpression(final boolean isStatement) { |
37732 | 1187 |
assert type == CLASS; |
41422 | 1188 |
final int classLineNumber = line; |
1189 |
final long classToken = token; |
|
37732 | 1190 |
next(); |
1191 |
||
1192 |
IdentNode className = null; |
|
1193 |
if (isStatement || type == IDENT) { |
|
1194 |
className = getIdent(); |
|
1195 |
} |
|
1196 |
||
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1197 |
return classTail(classLineNumber, classToken, className, isStatement); |
37732 | 1198 |
} |
1199 |
||
1200 |
private static final class ClassElementKey { |
|
1201 |
private final boolean isStatic; |
|
1202 |
private final String propertyName; |
|
1203 |
||
41422 | 1204 |
private ClassElementKey(final boolean isStatic, final String propertyName) { |
37732 | 1205 |
this.isStatic = isStatic; |
1206 |
this.propertyName = propertyName; |
|
1207 |
} |
|
1208 |
||
1209 |
@Override |
|
1210 |
public int hashCode() { |
|
1211 |
final int prime = 31; |
|
1212 |
int result = 1; |
|
1213 |
result = prime * result + (isStatic ? 1231 : 1237); |
|
1214 |
result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); |
|
1215 |
return result; |
|
1216 |
} |
|
1217 |
||
1218 |
@Override |
|
41422 | 1219 |
public boolean equals(final Object obj) { |
37732 | 1220 |
if (obj instanceof ClassElementKey) { |
41422 | 1221 |
final ClassElementKey other = (ClassElementKey) obj; |
37732 | 1222 |
return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName); |
1223 |
} |
|
1224 |
return false; |
|
1225 |
} |
|
1226 |
} |
|
1227 |
||
1228 |
/** |
|
1229 |
* Parse ClassTail and ClassBody. |
|
1230 |
* |
|
1231 |
* ClassTail[Yield] : |
|
1232 |
* ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } |
|
1233 |
* ClassHeritage[Yield] : |
|
1234 |
* extends LeftHandSideExpression[?Yield] |
|
1235 |
* |
|
1236 |
* ClassBody[Yield] : |
|
1237 |
* ClassElementList[?Yield] |
|
1238 |
* ClassElementList[Yield] : |
|
1239 |
* ClassElement[?Yield] |
|
1240 |
* ClassElementList[?Yield] ClassElement[?Yield] |
|
1241 |
* ClassElement[Yield] : |
|
1242 |
* MethodDefinition[?Yield] |
|
1243 |
* static MethodDefinition[?Yield] |
|
1244 |
* ; |
|
1245 |
*/ |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1246 |
private ClassNode classTail(final int classLineNumber, final long classToken, |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1247 |
final IdentNode className, final boolean isStatement) { |
37732 | 1248 |
final boolean oldStrictMode = isStrictMode; |
1249 |
isStrictMode = true; |
|
1250 |
try { |
|
1251 |
Expression classHeritage = null; |
|
1252 |
if (type == EXTENDS) { |
|
1253 |
next(); |
|
1254 |
classHeritage = leftHandSideExpression(); |
|
1255 |
} |
|
1256 |
||
1257 |
expect(LBRACE); |
|
1258 |
||
1259 |
PropertyNode constructor = null; |
|
1260 |
final ArrayList<PropertyNode> classElements = new ArrayList<>(); |
|
1261 |
final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>(); |
|
1262 |
for (;;) { |
|
1263 |
if (type == SEMICOLON) { |
|
1264 |
next(); |
|
1265 |
continue; |
|
1266 |
} |
|
1267 |
if (type == RBRACE) { |
|
1268 |
break; |
|
1269 |
} |
|
1270 |
final long classElementToken = token; |
|
1271 |
boolean isStatic = false; |
|
1272 |
if (type == STATIC) { |
|
1273 |
isStatic = true; |
|
1274 |
next(); |
|
1275 |
} |
|
1276 |
boolean generator = false; |
|
1277 |
if (isES6() && type == MUL) { |
|
1278 |
generator = true; |
|
1279 |
next(); |
|
1280 |
} |
|
1281 |
final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator); |
|
1282 |
if (classElement.isComputed()) { |
|
1283 |
classElements.add(classElement); |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1284 |
} else if (!classElement.isStatic() && classElement.getKeyName().equals(CONSTRUCTOR_NAME)) { |
37732 | 1285 |
if (constructor == null) { |
1286 |
constructor = classElement; |
|
1287 |
} else { |
|
1288 |
throw error(AbstractParser.message("multiple.constructors"), classElementToken); |
|
1289 |
} |
|
1290 |
} else { |
|
1291 |
// Check for duplicate method definitions and combine accessor methods. |
|
1292 |
// In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names). |
|
1293 |
||
1294 |
final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName()); |
|
1295 |
final Integer existing = keyToIndexMap.get(key); |
|
1296 |
||
1297 |
if (existing == null) { |
|
1298 |
keyToIndexMap.put(key, classElements.size()); |
|
1299 |
classElements.add(classElement); |
|
1300 |
} else { |
|
1301 |
final PropertyNode existingProperty = classElements.get(existing); |
|
1302 |
||
1303 |
final Expression value = classElement.getValue(); |
|
1304 |
final FunctionNode getter = classElement.getGetter(); |
|
1305 |
final FunctionNode setter = classElement.getSetter(); |
|
1306 |
||
1307 |
if (value != null || existingProperty.getValue() != null) { |
|
1308 |
keyToIndexMap.put(key, classElements.size()); |
|
1309 |
classElements.add(classElement); |
|
1310 |
} else if (getter != null) { |
|
1311 |
assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; |
|
1312 |
classElements.set(existing, existingProperty.setGetter(getter)); |
|
1313 |
} else if (setter != null) { |
|
1314 |
assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; |
|
1315 |
classElements.set(existing, existingProperty.setSetter(setter)); |
|
1316 |
} |
|
1317 |
} |
|
1318 |
} |
|
1319 |
} |
|
1320 |
||
1321 |
final long lastToken = token; |
|
1322 |
expect(RBRACE); |
|
1323 |
||
1324 |
if (constructor == null) { |
|
1325 |
constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null); |
|
1326 |
} |
|
1327 |
||
1328 |
classElements.trimToSize(); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1329 |
return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements, isStatement); |
37732 | 1330 |
} finally { |
1331 |
isStrictMode = oldStrictMode; |
|
1332 |
} |
|
1333 |
} |
|
1334 |
||
41422 | 1335 |
private PropertyNode createDefaultClassConstructor(final int classLineNumber, final long classToken, final long lastToken, final IdentNode className, final boolean subclass) { |
37732 | 1336 |
final int ctorFinish = finish; |
1337 |
final List<Statement> statements; |
|
1338 |
final List<IdentNode> parameters; |
|
1339 |
final long identToken = Token.recast(classToken, TokenType.IDENT); |
|
1340 |
if (subclass) { |
|
1341 |
final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper(); |
|
1342 |
final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter(); |
|
1343 |
final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent); |
|
1344 |
final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false); |
|
1345 |
statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall)); |
|
1346 |
parameters = Collections.singletonList(argsIdent); |
|
1347 |
} else { |
|
1348 |
statements = Collections.emptyList(); |
|
1349 |
parameters = Collections.emptyList(); |
|
1350 |
} |
|
1351 |
||
1352 |
final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements); |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1353 |
final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, CONSTRUCTOR_NAME); |
37732 | 1354 |
final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters); |
1355 |
function.setLastToken(lastToken); |
|
1356 |
||
1357 |
function.setFlag(FunctionNode.ES6_IS_METHOD); |
|
1358 |
function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR); |
|
1359 |
if (subclass) { |
|
1360 |
function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR); |
|
1361 |
function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); |
|
1362 |
} |
|
1363 |
if (className == null) { |
|
1364 |
function.setFlag(FunctionNode.IS_ANONYMOUS); |
|
1365 |
} |
|
1366 |
||
1367 |
final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode( |
|
1368 |
function, |
|
1369 |
classToken, |
|
1370 |
ctorName, |
|
1371 |
parameters, |
|
1372 |
FunctionNode.Kind.NORMAL, |
|
1373 |
classLineNumber, |
|
1374 |
body |
|
1375 |
), null, null, false, false); |
|
1376 |
return constructor; |
|
1377 |
} |
|
1378 |
||
1379 |
private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) { |
|
1380 |
final long methodToken = token; |
|
1381 |
final int methodLine = line; |
|
1382 |
final boolean computed = type == LBRACKET; |
|
1383 |
final boolean isIdent = type == IDENT; |
|
1384 |
final Expression propertyName = propertyName(); |
|
1385 |
int flags = FunctionNode.ES6_IS_METHOD; |
|
1386 |
if (!computed) { |
|
1387 |
final String name = ((PropertyKey)propertyName).getPropertyName(); |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1388 |
if (!generator && isIdent && type != LPAREN && name.equals(GET_NAME)) { |
37732 | 1389 |
final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags); |
1390 |
verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); |
|
1391 |
return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed); |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1392 |
} else if (!generator && isIdent && type != LPAREN && name.equals(SET_NAME)) { |
37732 | 1393 |
final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags); |
1394 |
verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); |
|
1395 |
return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed); |
|
1396 |
} else { |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1397 |
if (!isStatic && !generator && name.equals(CONSTRUCTOR_NAME)) { |
37732 | 1398 |
flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR; |
1399 |
if (subclass) { |
|
1400 |
flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR; |
|
1401 |
} |
|
1402 |
} |
|
1403 |
verifyAllowedMethodName(propertyName, isStatic, computed, generator, false); |
|
1404 |
} |
|
1405 |
} |
|
1406 |
final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed); |
|
1407 |
return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed); |
|
1408 |
} |
|
1409 |
||
1410 |
/** |
|
1411 |
* ES6 14.5.1 Static Semantics: Early Errors. |
|
1412 |
*/ |
|
1413 |
private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) { |
|
1414 |
if (!computed) { |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1415 |
if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals(CONSTRUCTOR_NAME)) { |
37732 | 1416 |
throw error(AbstractParser.message("generator.constructor"), key.getToken()); |
1417 |
} |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
1418 |
if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals(CONSTRUCTOR_NAME)) { |
37732 | 1419 |
throw error(AbstractParser.message("accessor.constructor"), key.getToken()); |
1420 |
} |
|
1421 |
if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) { |
|
1422 |
throw error(AbstractParser.message("static.prototype.method"), key.getToken()); |
|
1423 |
} |
|
1424 |
} |
|
1425 |
} |
|
1426 |
||
1427 |
/** |
|
16147 | 1428 |
* block : |
1429 |
* { StatementList? } |
|
1430 |
* |
|
1431 |
* see 12.1 |
|
1432 |
* |
|
1433 |
* Parse a statement block. |
|
1434 |
*/ |
|
1435 |
private void block() { |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1436 |
appendStatement(new BlockStatement(line, getBlock(true))); |
16147 | 1437 |
} |
1438 |
||
1439 |
/** |
|
1440 |
* StatementList : |
|
1441 |
* Statement |
|
1442 |
* StatementList Statement |
|
1443 |
* |
|
1444 |
* See 12.1 |
|
1445 |
* |
|
1446 |
* Parse a list of statements. |
|
1447 |
*/ |
|
1448 |
private void statementList() { |
|
1449 |
// Accumulate statements until end of list. */ |
|
37732 | 1450 |
loop: |
16147 | 1451 |
while (type != EOF) { |
1452 |
switch (type) { |
|
1453 |
case EOF: |
|
1454 |
case CASE: |
|
1455 |
case DEFAULT: |
|
1456 |
case RBRACE: |
|
1457 |
break loop; |
|
1458 |
default: |
|
1459 |
break; |
|
1460 |
} |
|
1461 |
||
1462 |
// Get next statement. |
|
1463 |
statement(); |
|
1464 |
} |
|
1465 |
} |
|
1466 |
||
1467 |
/** |
|
37732 | 1468 |
* Make sure that the identifier name used is allowed. |
1469 |
* |
|
1470 |
* @param ident Identifier that is verified |
|
1471 |
* @param contextString String used in error message to give context to the user |
|
1472 |
*/ |
|
1473 |
private void verifyIdent(final IdentNode ident, final String contextString) { |
|
1474 |
verifyStrictIdent(ident, contextString); |
|
1475 |
if (isES6()) { |
|
1476 |
final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length()); |
|
1477 |
if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) { |
|
1478 |
throw error(expectMessage(IDENT)); |
|
1479 |
} |
|
1480 |
} |
|
1481 |
} |
|
1482 |
||
1483 |
/** |
|
16147 | 1484 |
* Make sure that in strict mode, the identifier name used is allowed. |
1485 |
* |
|
1486 |
* @param ident Identifier that is verified |
|
1487 |
* @param contextString String used in error message to give context to the user |
|
1488 |
*/ |
|
1489 |
private void verifyStrictIdent(final IdentNode ident, final String contextString) { |
|
1490 |
if (isStrictMode) { |
|
1491 |
switch (ident.getName()) { |
|
1492 |
case "eval": |
|
1493 |
case "arguments": |
|
17233 | 1494 |
throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); |
16147 | 1495 |
default: |
1496 |
break; |
|
1497 |
} |
|
20571
f52b0abf5d88
8026039: future strict names are allowed as function name and argument name of a strict function
sundar
parents:
20559
diff
changeset
|
1498 |
|
f52b0abf5d88
8026039: future strict names are allowed as function name and argument name of a strict function
sundar
parents:
20559
diff
changeset
|
1499 |
if (ident.isFutureStrictName()) { |
f52b0abf5d88
8026039: future strict names are allowed as function name and argument name of a strict function
sundar
parents:
20559
diff
changeset
|
1500 |
throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); |
f52b0abf5d88
8026039: future strict names are allowed as function name and argument name of a strict function
sundar
parents:
20559
diff
changeset
|
1501 |
} |
16147 | 1502 |
} |
1503 |
} |
|
1504 |
||
36696 | 1505 |
/* |
16147 | 1506 |
* VariableStatement : |
1507 |
* var VariableDeclarationList ; |
|
1508 |
* |
|
1509 |
* VariableDeclarationList : |
|
1510 |
* VariableDeclaration |
|
1511 |
* VariableDeclarationList , VariableDeclaration |
|
1512 |
* |
|
1513 |
* VariableDeclaration : |
|
1514 |
* Identifier Initializer? |
|
1515 |
* |
|
1516 |
* Initializer : |
|
1517 |
* = AssignmentExpression |
|
1518 |
* |
|
1519 |
* See 12.2 |
|
1520 |
* |
|
1521 |
* Parse a VAR statement. |
|
1522 |
* @param isStatement True if a statement (not used in a FOR.) |
|
1523 |
*/ |
|
37732 | 1524 |
private void variableStatement(final TokenType varType) { |
1525 |
variableDeclarationList(varType, true, -1); |
|
29539
b2a8fb583979
8075448: nashorn parser API returns init variable tree object of a for loop after for loop statement tree object
sundar
parents:
29407
diff
changeset
|
1526 |
} |
b2a8fb583979
8075448: nashorn parser API returns init variable tree object of a for loop after for loop statement tree object
sundar
parents:
29407
diff
changeset
|
1527 |
|
41425 | 1528 |
private static final class ForVariableDeclarationListResult { |
1529 |
/** First missing const or binding pattern initializer. */ |
|
1530 |
Expression missingAssignment; |
|
1531 |
/** First declaration with an initializer. */ |
|
1532 |
long declarationWithInitializerToken; |
|
1533 |
/** Destructuring assignments. */ |
|
1534 |
Expression init; |
|
1535 |
Expression firstBinding; |
|
1536 |
Expression secondBinding; |
|
1537 |
||
1538 |
void recordMissingAssignment(final Expression binding) { |
|
1539 |
if (missingAssignment == null) { |
|
1540 |
missingAssignment = binding; |
|
1541 |
} |
|
1542 |
} |
|
1543 |
||
1544 |
void recordDeclarationWithInitializer(final long token) { |
|
1545 |
if (declarationWithInitializerToken == 0L) { |
|
1546 |
declarationWithInitializerToken = token; |
|
1547 |
} |
|
1548 |
} |
|
1549 |
||
1550 |
void addBinding(final Expression binding) { |
|
1551 |
if (firstBinding == null) { |
|
1552 |
firstBinding = binding; |
|
1553 |
} else if (secondBinding == null) { |
|
1554 |
secondBinding = binding; |
|
1555 |
} |
|
1556 |
// ignore the rest |
|
1557 |
} |
|
1558 |
||
1559 |
void addAssignment(final Expression assignment) { |
|
1560 |
if (init == null) { |
|
1561 |
init = assignment; |
|
1562 |
} else { |
|
1563 |
init = new BinaryNode(Token.recast(init.getToken(), COMMARIGHT), init, assignment); |
|
1564 |
} |
|
1565 |
} |
|
1566 |
} |
|
1567 |
||
1568 |
/** |
|
1569 |
* @param isStatement {@code true} if a VariableStatement, {@code false} if a {@code for} loop VariableDeclarationList |
|
1570 |
*/ |
|
1571 |
private ForVariableDeclarationListResult variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) { |
|
16147 | 1572 |
// VAR tested in caller. |
37732 | 1573 |
assert varType == VAR || varType == LET || varType == CONST; |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1574 |
final int varLine = line; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1575 |
final long varToken = token; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1576 |
|
16147 | 1577 |
next(); |
1578 |
||
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1579 |
int varFlags = 0; |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1580 |
if (varType == LET) { |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1581 |
varFlags |= VarNode.IS_LET; |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1582 |
} else if (varType == CONST) { |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1583 |
varFlags |= VarNode.IS_CONST; |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1584 |
} |
16147 | 1585 |
|
41425 | 1586 |
final ForVariableDeclarationListResult forResult = isStatement ? null : new ForVariableDeclarationListResult(); |
16147 | 1587 |
while (true) { |
1588 |
// Get name of var. |
|
37732 | 1589 |
if (type == YIELD && inGeneratorFunction()) { |
1590 |
expect(IDENT); |
|
1591 |
} |
|
1592 |
||
1593 |
final String contextString = "variable name"; |
|
41425 | 1594 |
final Expression binding = bindingIdentifierOrPattern(contextString); |
37732 | 1595 |
final boolean isDestructuring = !(binding instanceof IdentNode); |
1596 |
if (isDestructuring) { |
|
1597 |
final int finalVarFlags = varFlags; |
|
1598 |
verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() { |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1599 |
@Override |
37732 | 1600 |
public void accept(final IdentNode identNode) { |
1601 |
verifyIdent(identNode, contextString); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1602 |
if (!env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1603 |
// don't bother adding a variable if we are just parsing! |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1604 |
final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1605 |
appendStatement(var); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1606 |
} |
37732 | 1607 |
} |
1608 |
}); |
|
1609 |
} |
|
16147 | 1610 |
|
1611 |
// Assume no init. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1612 |
Expression init = null; |
16147 | 1613 |
|
1614 |
// Look for initializer assignment. |
|
1615 |
if (type == ASSIGN) { |
|
41425 | 1616 |
if (!isStatement) { |
1617 |
forResult.recordDeclarationWithInitializer(varToken); |
|
1618 |
} |
|
16147 | 1619 |
next(); |
1620 |
||
1621 |
// Get initializer expression. Suppress IN if not statement. |
|
37732 | 1622 |
if (!isDestructuring) { |
1623 |
defaultNames.push(binding); |
|
1624 |
} |
|
24719 | 1625 |
try { |
1626 |
init = assignmentExpression(!isStatement); |
|
1627 |
} finally { |
|
37732 | 1628 |
if (!isDestructuring) { |
1629 |
defaultNames.pop(); |
|
1630 |
} |
|
24719 | 1631 |
} |
37732 | 1632 |
} else if (isStatement) { |
1633 |
if (isDestructuring) { |
|
1634 |
throw error(AbstractParser.message("missing.destructuring.assignment"), token); |
|
1635 |
} else if (varType == CONST) { |
|
1636 |
throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName())); |
|
1637 |
} |
|
1638 |
// else, if we are in a for loop, delay checking until we know the kind of loop |
|
16147 | 1639 |
} |
1640 |
||
37732 | 1641 |
if (!isDestructuring) { |
1642 |
assert init != null || varType != CONST || !isStatement; |
|
1643 |
final IdentNode ident = (IdentNode)binding; |
|
1644 |
if (!isStatement && ident.getName().equals("let")) { |
|
1645 |
throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1 |
|
1646 |
} |
|
1647 |
// Only set declaration flag on lexically scoped let/const as it adds runtime overhead. |
|
1648 |
final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident; |
|
41425 | 1649 |
if (!isStatement) { |
1650 |
if (init == null && varType == CONST) { |
|
1651 |
forResult.recordMissingAssignment(name); |
|
1652 |
} |
|
1653 |
forResult.addBinding(new IdentNode(name)); |
|
1654 |
} |
|
37732 | 1655 |
final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags); |
1656 |
appendStatement(var); |
|
1657 |
} else { |
|
1658 |
assert init != null || !isStatement; |
|
41425 | 1659 |
if (init != null) { |
1660 |
final Expression assignment = verifyAssignment(Token.recast(varToken, ASSIGN), binding, init); |
|
1661 |
if (isStatement) { |
|
1662 |
appendStatement(new ExpressionStatement(varLine, assignment.getToken(), finish, assignment, varType)); |
|
1663 |
} else { |
|
1664 |
forResult.addAssignment(assignment); |
|
1665 |
forResult.addBinding(assignment); |
|
37732 | 1666 |
} |
41425 | 1667 |
} else if (!isStatement) { |
1668 |
forResult.recordMissingAssignment(binding); |
|
1669 |
forResult.addBinding(binding); |
|
37732 | 1670 |
} |
1671 |
} |
|
16147 | 1672 |
|
1673 |
if (type != COMMARIGHT) { |
|
1674 |
break; |
|
1675 |
} |
|
1676 |
next(); |
|
1677 |
} |
|
1678 |
||
1679 |
// If is a statement then handle end of line. |
|
1680 |
if (isStatement) { |
|
1681 |
endOfLine(); |
|
1682 |
} |
|
1683 |
||
41425 | 1684 |
return forResult; |
37732 | 1685 |
} |
1686 |
||
1687 |
private boolean isBindingIdentifier() { |
|
1688 |
return type == IDENT || isNonStrictModeIdent(); |
|
1689 |
} |
|
1690 |
||
1691 |
private IdentNode bindingIdentifier(final String contextString) { |
|
1692 |
final IdentNode name = getIdent(); |
|
1693 |
verifyIdent(name, contextString); |
|
1694 |
return name; |
|
1695 |
} |
|
1696 |
||
1697 |
private Expression bindingPattern() { |
|
1698 |
if (type == LBRACKET) { |
|
1699 |
return arrayLiteral(); |
|
1700 |
} else if (type == LBRACE) { |
|
1701 |
return objectLiteral(); |
|
1702 |
} else { |
|
1703 |
throw error(AbstractParser.message("expected.binding")); |
|
1704 |
} |
|
1705 |
} |
|
1706 |
||
1707 |
private Expression bindingIdentifierOrPattern(final String contextString) { |
|
1708 |
if (isBindingIdentifier() || !isES6()) { |
|
1709 |
return bindingIdentifier(contextString); |
|
1710 |
} else { |
|
1711 |
return bindingPattern(); |
|
1712 |
} |
|
1713 |
} |
|
1714 |
||
41425 | 1715 |
private abstract class VerifyDestructuringPatternNodeVisitor extends NodeVisitor<LexicalContext> { |
1716 |
VerifyDestructuringPatternNodeVisitor(final LexicalContext lc) { |
|
1717 |
super(lc); |
|
1718 |
} |
|
1719 |
||
1720 |
@Override |
|
1721 |
public boolean enterLiteralNode(final LiteralNode<?> literalNode) { |
|
1722 |
if (literalNode.isArray()) { |
|
1723 |
if (((LiteralNode.ArrayLiteralNode)literalNode).hasSpread() && ((LiteralNode.ArrayLiteralNode)literalNode).hasTrailingComma()) { |
|
1724 |
throw error("Rest element must be last", literalNode.getElementExpressions().get(literalNode.getElementExpressions().size() - 1).getToken()); |
|
1725 |
} |
|
1726 |
boolean restElement = false; |
|
1727 |
for (final Expression element : literalNode.getElementExpressions()) { |
|
1728 |
if (element != null) { |
|
1729 |
if (restElement) { |
|
1730 |
throw error("Unexpected element after rest element", element.getToken()); |
|
1731 |
} |
|
1732 |
if (element.isTokenType(SPREAD_ARRAY)) { |
|
1733 |
restElement = true; |
|
1734 |
final Expression lvalue = ((UnaryNode) element).getExpression(); |
|
1735 |
verifySpreadElement(lvalue); |
|
1736 |
} |
|
1737 |
element.accept(this); |
|
1738 |
} |
|
1739 |
} |
|
1740 |
return false; |
|
1741 |
} else { |
|
1742 |
return enterDefault(literalNode); |
|
1743 |
} |
|
1744 |
} |
|
1745 |
||
1746 |
protected abstract void verifySpreadElement(Expression lvalue); |
|
1747 |
||
1748 |
@Override |
|
1749 |
public boolean enterObjectNode(final ObjectNode objectNode) { |
|
1750 |
return true; |
|
1751 |
} |
|
1752 |
||
1753 |
@Override |
|
1754 |
public boolean enterPropertyNode(final PropertyNode propertyNode) { |
|
1755 |
if (propertyNode.getValue() != null) { |
|
1756 |
propertyNode.getValue().accept(this); |
|
1757 |
return false; |
|
1758 |
} else { |
|
1759 |
return enterDefault(propertyNode); |
|
1760 |
} |
|
1761 |
} |
|
1762 |
||
1763 |
@Override |
|
1764 |
public boolean enterBinaryNode(final BinaryNode binaryNode) { |
|
1765 |
if (binaryNode.isTokenType(ASSIGN)) { |
|
1766 |
binaryNode.lhs().accept(this); |
|
1767 |
// Initializer(rhs) can be any AssignmentExpression |
|
1768 |
return false; |
|
1769 |
} else { |
|
1770 |
return enterDefault(binaryNode); |
|
1771 |
} |
|
1772 |
} |
|
1773 |
||
1774 |
@Override |
|
1775 |
public boolean enterUnaryNode(final UnaryNode unaryNode) { |
|
1776 |
if (unaryNode.isTokenType(SPREAD_ARRAY)) { |
|
1777 |
// rest element |
|
1778 |
return true; |
|
1779 |
} else { |
|
1780 |
return enterDefault(unaryNode); |
|
1781 |
} |
|
1782 |
} |
|
1783 |
} |
|
1784 |
||
37732 | 1785 |
/** |
1786 |
* Verify destructuring variable declaration binding pattern and extract bound variable declarations. |
|
1787 |
*/ |
|
1788 |
private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) { |
|
41425 | 1789 |
assert (pattern instanceof BinaryNode && pattern.isTokenType(ASSIGN)) || |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
1790 |
pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; |
41425 | 1791 |
pattern.accept(new VerifyDestructuringPatternNodeVisitor(new LexicalContext()) { |
37732 | 1792 |
@Override |
41425 | 1793 |
protected void verifySpreadElement(final Expression lvalue) { |
1794 |
if (lvalue instanceof IdentNode) { |
|
1795 |
// checked in identifierCallback |
|
1796 |
} else if (isDestructuringLhs(lvalue)) { |
|
1797 |
verifyDestructuringBindingPattern(lvalue, identifierCallback); |
|
37732 | 1798 |
} else { |
41425 | 1799 |
throw error("Expected a valid binding identifier", lvalue.getToken()); |
37732 | 1800 |
} |
1801 |
} |
|
1802 |
||
1803 |
@Override |
|
1804 |
public boolean enterIdentNode(final IdentNode identNode) { |
|
1805 |
identifierCallback.accept(identNode); |
|
1806 |
return false; |
|
1807 |
} |
|
1808 |
||
1809 |
@Override |
|
1810 |
protected boolean enterDefault(final Node node) { |
|
1811 |
throw error(String.format("unexpected node in BindingPattern: %s", node)); |
|
1812 |
} |
|
1813 |
}); |
|
16147 | 1814 |
} |
1815 |
||
1816 |
/** |
|
1817 |
* EmptyStatement : |
|
1818 |
* ; |
|
1819 |
* |
|
1820 |
* See 12.3 |
|
1821 |
* |
|
1822 |
* Parse an empty statement. |
|
1823 |
*/ |
|
1824 |
private void emptyStatement() { |
|
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
1825 |
if (env._empty_statements) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1826 |
appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); |
16147 | 1827 |
} |
1828 |
||
1829 |
// SEMICOLON checked in caller. |
|
1830 |
next(); |
|
1831 |
} |
|
1832 |
||
1833 |
/** |
|
1834 |
* ExpressionStatement : |
|
37924
a78497edf9fb
8156714: Parsing issue with automatic semicolon insertion
hannesw
parents:
37923
diff
changeset
|
1835 |
* Expression ; // [lookahead ~({ or function )] |
16147 | 1836 |
* |
1837 |
* See 12.4 |
|
1838 |
* |
|
1839 |
* Parse an expression used in a statement block. |
|
1840 |
*/ |
|
1841 |
private void expressionStatement() { |
|
1842 |
// Lookahead checked in caller. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1843 |
final int expressionLine = line; |
16147 | 1844 |
final long expressionToken = token; |
1845 |
||
1846 |
// Get expression and add as statement. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1847 |
final Expression expression = expression(); |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1848 |
|
16147 | 1849 |
if (expression != null) { |
41422 | 1850 |
final ExpressionStatement expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1851 |
appendStatement(expressionStatement); |
16147 | 1852 |
} else { |
1853 |
expect(null); |
|
1854 |
} |
|
1855 |
||
1856 |
endOfLine(); |
|
1857 |
} |
|
1858 |
||
1859 |
/** |
|
1860 |
* IfStatement : |
|
1861 |
* if ( Expression ) Statement else Statement |
|
1862 |
* if ( Expression ) Statement |
|
1863 |
* |
|
1864 |
* See 12.5 |
|
1865 |
* |
|
1866 |
* Parse an IF statement. |
|
1867 |
*/ |
|
1868 |
private void ifStatement() { |
|
1869 |
// Capture IF token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1870 |
final int ifLine = line; |
16147 | 1871 |
final long ifToken = token; |
1872 |
// IF tested in caller. |
|
1873 |
next(); |
|
1874 |
||
1875 |
expect(LPAREN); |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
1876 |
final Expression test = expression(); |
16147 | 1877 |
expect(RPAREN); |
1878 |
final Block pass = getStatement(); |
|
1879 |
||
1880 |
Block fail = null; |
|
1881 |
if (type == ELSE) { |
|
1882 |
next(); |
|
1883 |
fail = getStatement(); |
|
1884 |
} |
|
1885 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1886 |
appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); |
16147 | 1887 |
} |
1888 |
||
1889 |
/** |
|
1890 |
* ... IterationStatement: |
|
1891 |
* ... |
|
1892 |
* for ( Expression[NoIn]?; Expression? ; Expression? ) Statement |
|
1893 |
* for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement |
|
1894 |
* for ( LeftHandSideExpression in Expression ) Statement |
|
1895 |
* for ( var VariableDeclaration[NoIn] in Expression ) Statement |
|
1896 |
* |
|
1897 |
* See 12.6 |
|
1898 |
* |
|
1899 |
* Parse a FOR statement. |
|
1900 |
*/ |
|
36696 | 1901 |
@SuppressWarnings("fallthrough") |
16147 | 1902 |
private void forStatement() { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1903 |
final long forToken = token; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1904 |
final int forLine = line; |
29539
b2a8fb583979
8075448: nashorn parser API returns init variable tree object of a for loop after for loop statement tree object
sundar
parents:
29407
diff
changeset
|
1905 |
// start position of this for statement. This is used |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
1906 |
// for sort order for variables declared in the initializer |
29539
b2a8fb583979
8075448: nashorn parser API returns init variable tree object of a for loop after for loop statement tree object
sundar
parents:
29407
diff
changeset
|
1907 |
// part of this 'for' statement (if any). |
b2a8fb583979
8075448: nashorn parser API returns init variable tree object of a for loop after for loop statement tree object
sundar
parents:
29407
diff
changeset
|
1908 |
final int forStart = Token.descPosition(forToken); |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1909 |
// When ES6 for-let is enabled we create a container block to capture the LET. |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1910 |
final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1911 |
|
16147 | 1912 |
// Create FOR node, capturing FOR token. |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1913 |
final ParserContextLoopNode forNode = new ParserContextLoopNode(); |
17233 | 1914 |
lc.push(forNode); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1915 |
Block body = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1916 |
Expression init = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1917 |
JoinPredecessorExpression test = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1918 |
JoinPredecessorExpression modify = null; |
41425 | 1919 |
ForVariableDeclarationListResult varDeclList = null; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1920 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1921 |
int flags = 0; |
36696 | 1922 |
boolean isForOf = false; |
16147 | 1923 |
|
1924 |
try { |
|
1925 |
// FOR tested in caller. |
|
1926 |
next(); |
|
1927 |
||
1928 |
// Nashorn extension: for each expression. |
|
1929 |
// iterate property values rather than property names. |
|
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
1930 |
if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1931 |
flags |= ForNode.IS_FOR_EACH; |
16147 | 1932 |
next(); |
1933 |
} |
|
1934 |
||
1935 |
expect(LPAREN); |
|
1936 |
||
41425 | 1937 |
TokenType varType = null; |
17233 | 1938 |
switch (type) { |
1939 |
case VAR: |
|
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1940 |
// Var declaration captured in for outer block. |
41425 | 1941 |
varDeclList = variableDeclarationList(varType = type, false, forStart); |
17233 | 1942 |
break; |
1943 |
case SEMICOLON: |
|
1944 |
break; |
|
1945 |
default: |
|
37732 | 1946 |
if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) { |
36691
56a7257458e7
8151811: Const declarations do not work in for..in loops
hannesw
parents:
36690
diff
changeset
|
1947 |
flags |= ForNode.PER_ITERATION_SCOPE; |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1948 |
// LET/CONST declaration captured in container block created above. |
41425 | 1949 |
varDeclList = variableDeclarationList(varType = type, false, forStart); |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1950 |
break; |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
1951 |
} |
24279 | 1952 |
if (env._const_as_var && type == CONST) { |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
1953 |
// Var declaration captured in for outer block. |
41425 | 1954 |
varDeclList = variableDeclarationList(varType = TokenType.VAR, false, forStart); |
24279 | 1955 |
break; |
1956 |
} |
|
1957 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1958 |
init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); |
17233 | 1959 |
break; |
1960 |
} |
|
1961 |
||
1962 |
switch (type) { |
|
1963 |
case SEMICOLON: |
|
1964 |
// for (init; test; modify) |
|
41924
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1965 |
if (varDeclList != null) { |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1966 |
assert init == null; |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1967 |
init = varDeclList.init; |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1968 |
// late check for missing assignment, now we know it's a for (init; test; modify) loop |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1969 |
if (varDeclList.missingAssignment != null) { |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1970 |
if (varDeclList.missingAssignment instanceof IdentNode) { |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1971 |
throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)varDeclList.missingAssignment).getName())); |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1972 |
} else { |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1973 |
throw error(AbstractParser.message("missing.destructuring.assignment"), varDeclList.missingAssignment.getToken()); |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1974 |
} |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1975 |
} |
d55f24e8953e
8156619: Unimplemented ES6 features should result in clear Error being thrown
hannesw
parents:
41425
diff
changeset
|
1976 |
} |
18843 | 1977 |
|
1978 |
// for each (init; test; modify) is invalid |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1979 |
if ((flags & ForNode.IS_FOR_EACH) != 0) { |
18843 | 1980 |
throw error(AbstractParser.message("for.each.without.in"), token); |
1981 |
} |
|
1982 |
||
17233 | 1983 |
expect(SEMICOLON); |
1984 |
if (type != SEMICOLON) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1985 |
test = joinPredecessorExpression(); |
17233 | 1986 |
} |
1987 |
expect(SEMICOLON); |
|
1988 |
if (type != RPAREN) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
1989 |
modify = joinPredecessorExpression(); |
17233 | 1990 |
} |
1991 |
break; |
|
1992 |
||
36696 | 1993 |
case IDENT: |
1994 |
if (env._es6 && "of".equals(getValue())) { |
|
1995 |
isForOf = true; |
|
1996 |
// fall through |
|
1997 |
} else { |
|
1998 |
expect(SEMICOLON); // fail with expected message |
|
1999 |
break; |
|
2000 |
} |
|
17233 | 2001 |
case IN: |
36696 | 2002 |
flags |= isForOf ? ForNode.IS_FOR_OF : ForNode.IS_FOR_IN; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2003 |
test = new JoinPredecessorExpression(); |
41425 | 2004 |
if (varDeclList != null) { |
2005 |
// for (var|let|const ForBinding in|of expression) |
|
2006 |
if (varDeclList.secondBinding != null) { |
|
17233 | 2007 |
// for (var i, j in obj) is invalid |
41425 | 2008 |
throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), varDeclList.secondBinding.getToken()); |
17233 | 2009 |
} |
41425 | 2010 |
if (varDeclList.declarationWithInitializerToken != 0 && (isStrictMode || type != TokenType.IN || varType != VAR || varDeclList.init != null)) { |
2011 |
// ES5 legacy: for (var i = AssignmentExpressionNoIn in Expression) |
|
2012 |
// Invalid in ES6, but allow it in non-strict mode if no ES6 features used, |
|
2013 |
// i.e., error if strict, for-of, let/const, or destructuring |
|
2014 |
throw error(AbstractParser.message("for.in.loop.initializer", isForOf ? "of" : "in"), varDeclList.declarationWithInitializerToken); |
|
2015 |
} |
|
2016 |
init = varDeclList.firstBinding; |
|
2017 |
assert init instanceof IdentNode || isDestructuringLhs(init); |
|
17233 | 2018 |
} else { |
2019 |
// for (expr in obj) |
|
36696 | 2020 |
assert init != null : "for..in/of init expression can not be null here"; |
17233 | 2021 |
|
2022 |
// check if initial expression is a valid L-value |
|
41425 | 2023 |
if (!checkValidLValue(init, isForOf ? "for-of iterator" : "for-in iterator")) { |
36696 | 2024 |
throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken()); |
17233 | 2025 |
} |
2026 |
} |
|
2027 |
||
2028 |
next(); |
|
2029 |
||
36696 | 2030 |
// For-of only allows AssignmentExpression. |
2031 |
modify = isForOf ? new JoinPredecessorExpression(assignmentExpression(false)) : joinPredecessorExpression(); |
|
17233 | 2032 |
break; |
2033 |
||
2034 |
default: |
|
2035 |
expect(SEMICOLON); |
|
2036 |
break; |
|
2037 |
} |
|
16147 | 2038 |
|
2039 |
expect(RPAREN); |
|
2040 |
||
2041 |
// Set the for body. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2042 |
body = getStatement(); |
16147 | 2043 |
} finally { |
17233 | 2044 |
lc.pop(forNode); |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2045 |
|
37732 | 2046 |
for (final Statement var : forNode.getStatements()) { |
2047 |
assert var instanceof VarNode; |
|
2048 |
appendStatement(var); |
|
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2049 |
} |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2050 |
if (body != null) { |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2051 |
appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2052 |
} |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2053 |
if (outer != null) { |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2054 |
restoreBlock(outer); |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2055 |
if (body != null) { |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2056 |
appendStatement(new BlockStatement(forLine, new Block( |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2057 |
outer.getToken(), |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2058 |
body.getFinish(), |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2059 |
outer.getStatements()))); |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2060 |
} |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2061 |
} |
16147 | 2062 |
} |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
2063 |
} |
16147 | 2064 |
|
37732 | 2065 |
private boolean checkValidLValue(final Expression init, final String contextString) { |
2066 |
if (init instanceof IdentNode) { |
|
2067 |
if (!checkIdentLValue((IdentNode)init)) { |
|
2068 |
return false; |
|
2069 |
} |
|
2070 |
verifyIdent((IdentNode)init, contextString); |
|
2071 |
return true; |
|
2072 |
} else if (init instanceof AccessNode || init instanceof IndexNode) { |
|
2073 |
return true; |
|
2074 |
} else if (isDestructuringLhs(init)) { |
|
2075 |
verifyDestructuringAssignmentPattern(init, contextString); |
|
2076 |
return true; |
|
2077 |
} else { |
|
2078 |
return false; |
|
2079 |
} |
|
2080 |
} |
|
2081 |
||
38485
8c55199bc96b
8157241: Remove javac warnings of Nashorn "ant clean test"
sundar
parents:
37924
diff
changeset
|
2082 |
@SuppressWarnings("fallthrough") |
37732 | 2083 |
private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) { |
2084 |
assert type == LET; |
|
2085 |
for (int i = 1;; i++) { |
|
41422 | 2086 |
final TokenType t = T(k + i); |
37732 | 2087 |
switch (t) { |
2088 |
case EOL: |
|
2089 |
case COMMENT: |
|
2090 |
continue; |
|
2091 |
case IDENT: |
|
2092 |
if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) { |
|
2093 |
return false; |
|
2094 |
} |
|
2095 |
// fall through |
|
2096 |
case LBRACKET: |
|
2097 |
case LBRACE: |
|
2098 |
return true; |
|
2099 |
default: |
|
2100 |
// accept future strict tokens in non-strict mode (including LET) |
|
2101 |
if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) { |
|
2102 |
return true; |
|
2103 |
} |
|
2104 |
return false; |
|
2105 |
} |
|
2106 |
} |
|
2107 |
} |
|
2108 |
||
16147 | 2109 |
/** |
2110 |
* ...IterationStatement : |
|
2111 |
* ... |
|
2112 |
* while ( Expression ) Statement |
|
2113 |
* ... |
|
2114 |
* |
|
2115 |
* See 12.6 |
|
2116 |
* |
|
2117 |
* Parse while statement. |
|
2118 |
*/ |
|
2119 |
private void whileStatement() { |
|
2120 |
// Capture WHILE token. |
|
2121 |
final long whileToken = token; |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2122 |
final int whileLine = line; |
16147 | 2123 |
// WHILE tested in caller. |
2124 |
next(); |
|
2125 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2126 |
final ParserContextLoopNode whileNode = new ParserContextLoopNode(); |
17233 | 2127 |
lc.push(whileNode); |
16147 | 2128 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2129 |
JoinPredecessorExpression test = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2130 |
Block body = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2131 |
|
16147 | 2132 |
try { |
2133 |
expect(LPAREN); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2134 |
test = joinPredecessorExpression(); |
16147 | 2135 |
expect(RPAREN); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2136 |
body = getStatement(); |
16147 | 2137 |
} finally { |
17233 | 2138 |
lc.pop(whileNode); |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2139 |
} |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2140 |
|
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2141 |
if (body != null) { |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2142 |
appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body)); |
16147 | 2143 |
} |
2144 |
} |
|
2145 |
||
2146 |
/** |
|
2147 |
* ...IterationStatement : |
|
2148 |
* ... |
|
2149 |
* do Statement while( Expression ) ; |
|
2150 |
* ... |
|
2151 |
* |
|
2152 |
* See 12.6 |
|
2153 |
* |
|
2154 |
* Parse DO WHILE statement. |
|
2155 |
*/ |
|
2156 |
private void doStatement() { |
|
2157 |
// Capture DO token. |
|
2158 |
final long doToken = token; |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2159 |
int doLine = 0; |
16147 | 2160 |
// DO tested in the caller. |
2161 |
next(); |
|
2162 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2163 |
final ParserContextLoopNode doWhileNode = new ParserContextLoopNode(); |
17233 | 2164 |
lc.push(doWhileNode); |
16147 | 2165 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2166 |
Block body = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2167 |
JoinPredecessorExpression test = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2168 |
|
16147 | 2169 |
try { |
2170 |
// Get DO body. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2171 |
body = getStatement(); |
16147 | 2172 |
|
2173 |
expect(WHILE); |
|
2174 |
expect(LPAREN); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2175 |
doLine = line; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2176 |
test = joinPredecessorExpression(); |
16147 | 2177 |
expect(RPAREN); |
2178 |
||
2179 |
if (type == SEMICOLON) { |
|
2180 |
endOfLine(); |
|
2181 |
} |
|
2182 |
} finally { |
|
17233 | 2183 |
lc.pop(doWhileNode); |
16147 | 2184 |
} |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2185 |
|
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2186 |
appendStatement(new WhileNode(doLine, doToken, finish, true, test, body)); |
16147 | 2187 |
} |
2188 |
||
2189 |
/** |
|
2190 |
* ContinueStatement : |
|
2191 |
* continue Identifier? ; // [no LineTerminator here] |
|
2192 |
* |
|
2193 |
* See 12.7 |
|
2194 |
* |
|
2195 |
* Parse CONTINUE statement. |
|
2196 |
*/ |
|
2197 |
private void continueStatement() { |
|
2198 |
// Capture CONTINUE token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2199 |
final int continueLine = line; |
16147 | 2200 |
final long continueToken = token; |
2201 |
// CONTINUE tested in caller. |
|
2202 |
nextOrEOL(); |
|
2203 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2204 |
ParserContextLabelNode labelNode = null; |
16147 | 2205 |
|
2206 |
// SEMICOLON or label. |
|
2207 |
switch (type) { |
|
2208 |
case RBRACE: |
|
2209 |
case SEMICOLON: |
|
2210 |
case EOL: |
|
18625
13558072545a
8019473: Parser issues related to functions and blocks
sundar
parents:
18335
diff
changeset
|
2211 |
case EOF: |
16147 | 2212 |
break; |
2213 |
||
2214 |
default: |
|
2215 |
final IdentNode ident = getIdent(); |
|
17233 | 2216 |
labelNode = lc.findLabel(ident.getName()); |
16147 | 2217 |
|
2218 |
if (labelNode == null) { |
|
17233 | 2219 |
throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
16147 | 2220 |
} |
2221 |
||
2222 |
break; |
|
2223 |
} |
|
2224 |
||
24751 | 2225 |
final String labelName = labelNode == null ? null : labelNode.getLabelName(); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2226 |
final ParserContextLoopNode targetNode = lc.getContinueTo(labelName); |
16147 | 2227 |
|
2228 |
if (targetNode == null) { |
|
17233 | 2229 |
throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); |
16147 | 2230 |
} |
2231 |
||
2232 |
endOfLine(); |
|
2233 |
||
2234 |
// Construct and add CONTINUE node. |
|
24751 | 2235 |
appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); |
16147 | 2236 |
} |
2237 |
||
2238 |
/** |
|
2239 |
* BreakStatement : |
|
2240 |
* break Identifier? ; // [no LineTerminator here] |
|
2241 |
* |
|
2242 |
* See 12.8 |
|
2243 |
* |
|
2244 |
*/ |
|
2245 |
private void breakStatement() { |
|
2246 |
// Capture BREAK token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2247 |
final int breakLine = line; |
16147 | 2248 |
final long breakToken = token; |
2249 |
// BREAK tested in caller. |
|
2250 |
nextOrEOL(); |
|
2251 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2252 |
ParserContextLabelNode labelNode = null; |
16147 | 2253 |
|
2254 |
// SEMICOLON or label. |
|
2255 |
switch (type) { |
|
2256 |
case RBRACE: |
|
2257 |
case SEMICOLON: |
|
2258 |
case EOL: |
|
18625
13558072545a
8019473: Parser issues related to functions and blocks
sundar
parents:
18335
diff
changeset
|
2259 |
case EOF: |
16147 | 2260 |
break; |
2261 |
||
2262 |
default: |
|
2263 |
final IdentNode ident = getIdent(); |
|
17233 | 2264 |
labelNode = lc.findLabel(ident.getName()); |
16147 | 2265 |
|
2266 |
if (labelNode == null) { |
|
17233 | 2267 |
throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
16147 | 2268 |
} |
2269 |
||
2270 |
break; |
|
2271 |
} |
|
2272 |
||
17233 | 2273 |
//either an explicit label - then get its node or just a "break" - get first breakable |
2274 |
//targetNode is what we are breaking out from. |
|
24751 | 2275 |
final String labelName = labelNode == null ? null : labelNode.getLabelName(); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2276 |
final ParserContextBreakableNode targetNode = lc.getBreakable(labelName); |
47038
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2277 |
|
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2278 |
if( targetNode instanceof ParserContextBlockNode) { |
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2279 |
targetNode.setFlag(Block.IS_BREAKABLE); |
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2280 |
} |
f57fa7f112a0
8177691: Labeled break in catch and finally works wrongly, when invoked through nashorn
sdama
parents:
46169
diff
changeset
|
2281 |
|
16147 | 2282 |
if (targetNode == null) { |
17233 | 2283 |
throw error(AbstractParser.message("illegal.break.stmt"), breakToken); |
16147 | 2284 |
} |
2285 |
||
2286 |
endOfLine(); |
|
2287 |
||
2288 |
// Construct and add BREAK node. |
|
24751 | 2289 |
appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); |
16147 | 2290 |
} |
2291 |
||
2292 |
/** |
|
2293 |
* ReturnStatement : |
|
2294 |
* return Expression? ; // [no LineTerminator here] |
|
2295 |
* |
|
2296 |
* See 12.9 |
|
2297 |
* |
|
2298 |
* Parse RETURN statement. |
|
2299 |
*/ |
|
2300 |
private void returnStatement() { |
|
2301 |
// check for return outside function |
|
37732 | 2302 |
if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) { |
17233 | 2303 |
throw error(AbstractParser.message("invalid.return")); |
16147 | 2304 |
} |
2305 |
||
2306 |
// Capture RETURN token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2307 |
final int returnLine = line; |
16147 | 2308 |
final long returnToken = token; |
2309 |
// RETURN tested in caller. |
|
2310 |
nextOrEOL(); |
|
2311 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2312 |
Expression expression = null; |
16147 | 2313 |
|
2314 |
// SEMICOLON or expression. |
|
2315 |
switch (type) { |
|
2316 |
case RBRACE: |
|
2317 |
case SEMICOLON: |
|
2318 |
case EOL: |
|
18625
13558072545a
8019473: Parser issues related to functions and blocks
sundar
parents:
18335
diff
changeset
|
2319 |
case EOF: |
16147 | 2320 |
break; |
2321 |
||
2322 |
default: |
|
2323 |
expression = expression(); |
|
2324 |
break; |
|
2325 |
} |
|
2326 |
||
2327 |
endOfLine(); |
|
2328 |
||
2329 |
// Construct and add RETURN node. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2330 |
appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); |
16147 | 2331 |
} |
2332 |
||
2333 |
/** |
|
37732 | 2334 |
* Parse YieldExpression. |
16147 | 2335 |
* |
37732 | 2336 |
* YieldExpression[In] : |
2337 |
* yield |
|
2338 |
* yield [no LineTerminator here] AssignmentExpression[?In, Yield] |
|
2339 |
* yield [no LineTerminator here] * AssignmentExpression[?In, Yield] |
|
16147 | 2340 |
*/ |
38485
8c55199bc96b
8157241: Remove javac warnings of Nashorn "ant clean test"
sundar
parents:
37924
diff
changeset
|
2341 |
@SuppressWarnings("fallthrough") |
37732 | 2342 |
private Expression yieldExpression(final boolean noIn) { |
2343 |
assert inGeneratorFunction(); |
|
16147 | 2344 |
// Capture YIELD token. |
37732 | 2345 |
long yieldToken = token; |
16147 | 2346 |
// YIELD tested in caller. |
37732 | 2347 |
assert type == YIELD; |
16147 | 2348 |
nextOrEOL(); |
2349 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2350 |
Expression expression = null; |
16147 | 2351 |
|
37732 | 2352 |
boolean yieldAsterisk = false; |
2353 |
if (type == MUL) { |
|
2354 |
yieldAsterisk = true; |
|
2355 |
yieldToken = Token.recast(yieldToken, YIELD_STAR); |
|
2356 |
next(); |
|
2357 |
} |
|
2358 |
||
16147 | 2359 |
switch (type) { |
2360 |
case RBRACE: |
|
2361 |
case SEMICOLON: |
|
2362 |
case EOL: |
|
18625
13558072545a
8019473: Parser issues related to functions and blocks
sundar
parents:
18335
diff
changeset
|
2363 |
case EOF: |
37732 | 2364 |
case COMMARIGHT: |
2365 |
case RPAREN: |
|
2366 |
case RBRACKET: |
|
2367 |
case COLON: |
|
2368 |
if (!yieldAsterisk) { |
|
2369 |
// treat (yield) as (yield void 0) |
|
2370 |
expression = newUndefinedLiteral(yieldToken, finish); |
|
2371 |
if (type == EOL) { |
|
2372 |
next(); |
|
2373 |
} |
|
2374 |
break; |
|
2375 |
} else { |
|
2376 |
// AssignmentExpression required, fall through |
|
2377 |
} |
|
16147 | 2378 |
|
2379 |
default: |
|
37732 | 2380 |
expression = assignmentExpression(noIn); |
16147 | 2381 |
break; |
2382 |
} |
|
2383 |
||
2384 |
// Construct and add YIELD node. |
|
37732 | 2385 |
return new UnaryNode(yieldToken, expression); |
2386 |
} |
|
2387 |
||
2388 |
private static UnaryNode newUndefinedLiteral(final long token, final int finish) { |
|
2389 |
return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0)); |
|
16147 | 2390 |
} |
2391 |
||
2392 |
/** |
|
2393 |
* WithStatement : |
|
2394 |
* with ( Expression ) Statement |
|
2395 |
* |
|
2396 |
* See 12.10 |
|
2397 |
* |
|
2398 |
* Parse WITH statement. |
|
2399 |
*/ |
|
2400 |
private void withStatement() { |
|
2401 |
// Capture WITH token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2402 |
final int withLine = line; |
16147 | 2403 |
final long withToken = token; |
2404 |
// WITH tested in caller. |
|
2405 |
next(); |
|
2406 |
||
2407 |
// ECMA 12.10.1 strict mode restrictions |
|
2408 |
if (isStrictMode) { |
|
17233 | 2409 |
throw error(AbstractParser.message("strict.no.with"), withToken); |
16147 | 2410 |
} |
2411 |
||
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2412 |
expect(LPAREN); |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2413 |
final Expression expression = expression(); |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2414 |
expect(RPAREN); |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2415 |
final Block body = getStatement(); |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2416 |
|
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2417 |
appendStatement(new WithNode(withLine, withToken, finish, expression, body)); |
16147 | 2418 |
} |
2419 |
||
2420 |
/** |
|
2421 |
* SwitchStatement : |
|
2422 |
* switch ( Expression ) CaseBlock |
|
2423 |
* |
|
2424 |
* CaseBlock : |
|
2425 |
* { CaseClauses? } |
|
2426 |
* { CaseClauses? DefaultClause CaseClauses } |
|
2427 |
* |
|
2428 |
* CaseClauses : |
|
2429 |
* CaseClause |
|
2430 |
* CaseClauses CaseClause |
|
2431 |
* |
|
2432 |
* CaseClause : |
|
2433 |
* case Expression : StatementList? |
|
2434 |
* |
|
2435 |
* DefaultClause : |
|
2436 |
* default : StatementList? |
|
2437 |
* |
|
2438 |
* See 12.11 |
|
2439 |
* |
|
2440 |
* Parse SWITCH statement. |
|
2441 |
*/ |
|
2442 |
private void switchStatement() { |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2443 |
final int switchLine = line; |
16147 | 2444 |
final long switchToken = token; |
37732 | 2445 |
|
2446 |
// Block to capture variables declared inside the switch statement. |
|
2447 |
final ParserContextBlockNode switchBlock = newBlock(); |
|
2448 |
||
16147 | 2449 |
// SWITCH tested in caller. |
2450 |
next(); |
|
2451 |
||
2452 |
// Create and add switch statement. |
|
37732 | 2453 |
final ParserContextSwitchNode switchNode = new ParserContextSwitchNode(); |
17233 | 2454 |
lc.push(switchNode); |
16147 | 2455 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2456 |
CaseNode defaultCase = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2457 |
// Prepare to accumulate cases. |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2458 |
final List<CaseNode> cases = new ArrayList<>(); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2459 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2460 |
Expression expression = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2461 |
|
16147 | 2462 |
try { |
2463 |
expect(LPAREN); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2464 |
expression = expression(); |
16147 | 2465 |
expect(RPAREN); |
2466 |
||
2467 |
expect(LBRACE); |
|
2468 |
||
2469 |
||
2470 |
while (type != RBRACE) { |
|
2471 |
// Prepare for next case. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2472 |
Expression caseExpression = null; |
16147 | 2473 |
final long caseToken = token; |
2474 |
||
2475 |
switch (type) { |
|
2476 |
case CASE: |
|
2477 |
next(); |
|
2478 |
caseExpression = expression(); |
|
2479 |
break; |
|
2480 |
||
2481 |
case DEFAULT: |
|
2482 |
if (defaultCase != null) { |
|
17233 | 2483 |
throw error(AbstractParser.message("duplicate.default.in.switch")); |
16147 | 2484 |
} |
2485 |
next(); |
|
2486 |
break; |
|
2487 |
||
2488 |
default: |
|
2489 |
// Force an error. |
|
2490 |
expect(CASE); |
|
2491 |
break; |
|
2492 |
} |
|
2493 |
||
2494 |
expect(COLON); |
|
2495 |
||
2496 |
// Get CASE body. |
|
37732 | 2497 |
final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList(); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2498 |
final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); |
16147 | 2499 |
|
2500 |
if (caseExpression == null) { |
|
2501 |
defaultCase = caseNode; |
|
2502 |
} |
|
2503 |
||
2504 |
cases.add(caseNode); |
|
2505 |
} |
|
2506 |
||
2507 |
next(); |
|
2508 |
} finally { |
|
17233 | 2509 |
lc.pop(switchNode); |
37732 | 2510 |
restoreBlock(switchBlock); |
16147 | 2511 |
} |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2512 |
|
37732 | 2513 |
final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase); |
2514 |
appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement))); |
|
16147 | 2515 |
} |
2516 |
||
2517 |
/** |
|
2518 |
* LabelledStatement : |
|
2519 |
* Identifier : Statement |
|
2520 |
* |
|
2521 |
* See 12.12 |
|
2522 |
* |
|
2523 |
* Parse label statement. |
|
2524 |
*/ |
|
2525 |
private void labelStatement() { |
|
2526 |
// Capture label token. |
|
2527 |
final long labelToken = token; |
|
2528 |
// Get label ident. |
|
2529 |
final IdentNode ident = getIdent(); |
|
2530 |
||
2531 |
expect(COLON); |
|
2532 |
||
17233 | 2533 |
if (lc.findLabel(ident.getName()) != null) { |
2534 |
throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); |
|
16147 | 2535 |
} |
2536 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2537 |
final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName()); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2538 |
Block body = null; |
16147 | 2539 |
try { |
17233 | 2540 |
lc.push(labelNode); |
37732 | 2541 |
body = getStatement(true); |
16147 | 2542 |
} finally { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2543 |
assert lc.peek() instanceof ParserContextLabelNode; |
17233 | 2544 |
lc.pop(labelNode); |
16147 | 2545 |
} |
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2546 |
|
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
2547 |
appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body)); |
16147 | 2548 |
} |
2549 |
||
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
2550 |
/** |
16147 | 2551 |
* ThrowStatement : |
2552 |
* throw Expression ; // [no LineTerminator here] |
|
2553 |
* |
|
2554 |
* See 12.13 |
|
2555 |
* |
|
2556 |
* Parse throw statement. |
|
2557 |
*/ |
|
2558 |
private void throwStatement() { |
|
2559 |
// Capture THROW token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2560 |
final int throwLine = line; |
16147 | 2561 |
final long throwToken = token; |
2562 |
// THROW tested in caller. |
|
2563 |
nextOrEOL(); |
|
2564 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2565 |
Expression expression = null; |
16147 | 2566 |
|
2567 |
// SEMICOLON or expression. |
|
2568 |
switch (type) { |
|
2569 |
case RBRACE: |
|
2570 |
case SEMICOLON: |
|
2571 |
case EOL: |
|
2572 |
break; |
|
2573 |
||
2574 |
default: |
|
2575 |
expression = expression(); |
|
2576 |
break; |
|
2577 |
} |
|
2578 |
||
2579 |
if (expression == null) { |
|
17233 | 2580 |
throw error(AbstractParser.message("expected.operand", type.getNameOrType())); |
16147 | 2581 |
} |
2582 |
||
2583 |
endOfLine(); |
|
2584 |
||
24751 | 2585 |
appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); |
16147 | 2586 |
} |
2587 |
||
2588 |
/** |
|
2589 |
* TryStatement : |
|
2590 |
* try Block Catch |
|
2591 |
* try Block Finally |
|
2592 |
* try Block Catch Finally |
|
2593 |
* |
|
2594 |
* Catch : |
|
2595 |
* catch( Identifier if Expression ) Block |
|
2596 |
* catch( Identifier ) Block |
|
2597 |
* |
|
2598 |
* Finally : |
|
2599 |
* finally Block |
|
2600 |
* |
|
2601 |
* See 12.14 |
|
2602 |
* |
|
2603 |
* Parse TRY statement. |
|
2604 |
*/ |
|
2605 |
private void tryStatement() { |
|
2606 |
// Capture TRY token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2607 |
final int tryLine = line; |
16147 | 2608 |
final long tryToken = token; |
2609 |
// TRY tested in caller. |
|
2610 |
next(); |
|
2611 |
||
16239
fbae49f786c6
8008215: break in catch clause causes java.lang.VerifyError: Inconsistent stackmap
hannesw
parents:
16237
diff
changeset
|
2612 |
// Container block needed to act as target for labeled break statements |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2613 |
final int startLine = line; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2614 |
final ParserContextBlockNode outer = newBlock(); |
16147 | 2615 |
// Create try. |
2616 |
||
2617 |
try { |
|
17233 | 2618 |
final Block tryBody = getBlock(true); |
16147 | 2619 |
final List<Block> catchBlocks = new ArrayList<>(); |
2620 |
||
2621 |
while (type == CATCH) { |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2622 |
final int catchLine = line; |
16147 | 2623 |
final long catchToken = token; |
2624 |
next(); |
|
2625 |
expect(LPAREN); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
2626 |
|
41983
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2627 |
// ES6 catch parameter can be a BindingIdentifier or a BindingPattern |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
2628 |
// http://www.ecma-international.org/ecma-262/6.0/ |
41983
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2629 |
final String contextString = "catch argument"; |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2630 |
final Expression exception = bindingIdentifierOrPattern(contextString); |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2631 |
final boolean isDestructuring = !(exception instanceof IdentNode); |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2632 |
if (isDestructuring) { |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2633 |
verifyDestructuringBindingPattern(exception, new Consumer<IdentNode>() { |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2634 |
@Override |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2635 |
public void accept(final IdentNode identNode) { |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2636 |
verifyIdent(identNode, contextString); |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2637 |
} |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2638 |
}); |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2639 |
} else { |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2640 |
// ECMA 12.4.1 strict mode restrictions |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2641 |
verifyStrictIdent((IdentNode) exception, "catch argument"); |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2642 |
} |
eb674141ab03
8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents:
41924
diff
changeset
|
2643 |
|
16147 | 2644 |
|
23766
a3ef17770bab
8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed
sundar
parents:
23372
diff
changeset
|
2645 |
// Nashorn extension: catch clause can have optional |
a3ef17770bab
8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed
sundar
parents:
23372
diff
changeset
|
2646 |
// condition. So, a single try can have more than one |
a3ef17770bab
8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed
sundar
parents:
23372
diff
changeset
|
2647 |
// catch clause each with it's own condition. |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2648 |
final Expression ifExpression; |
23766
a3ef17770bab
8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed
sundar
parents:
23372
diff
changeset
|
2649 |
if (!env._no_syntax_extensions && type == IF) { |
16147 | 2650 |
next(); |
2651 |
// Get the exception condition. |
|
2652 |
ifExpression = expression(); |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2653 |
} else { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2654 |
ifExpression = null; |
16147 | 2655 |
} |
2656 |
||
2657 |
expect(RPAREN); |
|
2658 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2659 |
final ParserContextBlockNode catchBlock = newBlock(); |
16147 | 2660 |
try { |
2661 |
// Get CATCH body. |
|
2662 |
final Block catchBody = getBlock(true); |
|
24751 | 2663 |
final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); |
17233 | 2664 |
appendStatement(catchNode); |
2665 |
} finally { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2666 |
restoreBlock(catchBlock); |
29407 | 2667 |
catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags() | Block.IS_SYNTHETIC, catchBlock.getStatements())); |
16147 | 2668 |
} |
2669 |
||
2670 |
// If unconditional catch then should to be the end. |
|
2671 |
if (ifExpression == null) { |
|
2672 |
break; |
|
2673 |
} |
|
2674 |
} |
|
2675 |
||
2676 |
// Prepare to capture finally statement. |
|
2677 |
Block finallyStatements = null; |
|
2678 |
||
2679 |
if (type == FINALLY) { |
|
2680 |
next(); |
|
2681 |
finallyStatements = getBlock(true); |
|
2682 |
} |
|
2683 |
||
2684 |
// Need at least one catch or a finally. |
|
2685 |
if (catchBlocks.isEmpty() && finallyStatements == null) { |
|
17233 | 2686 |
throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); |
16147 | 2687 |
} |
2688 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2689 |
final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements); |
17233 | 2690 |
// Add try. |
2691 |
assert lc.peek() == outer; |
|
2692 |
appendStatement(tryNode); |
|
16147 | 2693 |
} finally { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
2694 |
restoreBlock(outer); |
16147 | 2695 |
} |
16239
fbae49f786c6
8008215: break in catch clause causes java.lang.VerifyError: Inconsistent stackmap
hannesw
parents:
16237
diff
changeset
|
2696 |
|
29407 | 2697 |
appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags() | Block.IS_SYNTHETIC, outer.getStatements()))); |
16147 | 2698 |
} |
2699 |
||
2700 |
/** |
|
2701 |
* DebuggerStatement : |
|
2702 |
* debugger ; |
|
2703 |
* |
|
2704 |
* See 12.15 |
|
2705 |
* |
|
2706 |
* Parse debugger statement. |
|
2707 |
*/ |
|
2708 |
private void debuggerStatement() { |
|
2709 |
// Capture DEBUGGER token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2710 |
final int debuggerLine = line; |
16147 | 2711 |
final long debuggerToken = token; |
2712 |
// DEBUGGER tested in caller. |
|
2713 |
next(); |
|
2714 |
endOfLine(); |
|
29407 | 2715 |
appendStatement(new DebuggerNode(debuggerLine, debuggerToken, finish)); |
16147 | 2716 |
} |
2717 |
||
2718 |
/** |
|
2719 |
* PrimaryExpression : |
|
2720 |
* this |
|
37732 | 2721 |
* IdentifierReference |
16147 | 2722 |
* Literal |
2723 |
* ArrayLiteral |
|
2724 |
* ObjectLiteral |
|
33414 | 2725 |
* RegularExpressionLiteral |
2726 |
* TemplateLiteral |
|
37732 | 2727 |
* CoverParenthesizedExpressionAndArrowParameterList |
2728 |
* |
|
2729 |
* CoverParenthesizedExpressionAndArrowParameterList : |
|
16147 | 2730 |
* ( Expression ) |
37732 | 2731 |
* ( ) |
2732 |
* ( ... BindingIdentifier ) |
|
2733 |
* ( Expression , ... BindingIdentifier ) |
|
16147 | 2734 |
* |
2735 |
* Parse primary expression. |
|
2736 |
* @return Expression node. |
|
2737 |
*/ |
|
2738 |
@SuppressWarnings("fallthrough") |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2739 |
private Expression primaryExpression() { |
16147 | 2740 |
// Capture first token. |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2741 |
final int primaryLine = line; |
16147 | 2742 |
final long primaryToken = token; |
2743 |
||
2744 |
switch (type) { |
|
2745 |
case THIS: |
|
2746 |
final String name = type.getName(); |
|
2747 |
next(); |
|
37732 | 2748 |
markThis(lc); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2749 |
return new IdentNode(primaryToken, finish, name); |
16147 | 2750 |
case IDENT: |
2751 |
final IdentNode ident = getIdent(); |
|
2752 |
if (ident == null) { |
|
2753 |
break; |
|
2754 |
} |
|
2755 |
detectSpecialProperty(ident); |
|
2756 |
return ident; |
|
32444 | 2757 |
case OCTAL_LEGACY: |
16147 | 2758 |
if (isStrictMode) { |
17233 | 2759 |
throw error(AbstractParser.message("strict.no.octal"), token); |
16147 | 2760 |
} |
2761 |
case STRING: |
|
2762 |
case ESCSTRING: |
|
2763 |
case DECIMAL: |
|
2764 |
case HEXADECIMAL: |
|
32444 | 2765 |
case OCTAL: |
2766 |
case BINARY_NUMBER: |
|
16147 | 2767 |
case FLOATING: |
2768 |
case REGEX: |
|
2769 |
case XML: |
|
2770 |
return getLiteral(); |
|
16211 | 2771 |
case EXECSTRING: |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2772 |
return execString(primaryLine, primaryToken); |
16147 | 2773 |
case FALSE: |
2774 |
next(); |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2775 |
return LiteralNode.newInstance(primaryToken, finish, false); |
16147 | 2776 |
case TRUE: |
2777 |
next(); |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2778 |
return LiteralNode.newInstance(primaryToken, finish, true); |
16147 | 2779 |
case NULL: |
2780 |
next(); |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2781 |
return LiteralNode.newInstance(primaryToken, finish); |
16147 | 2782 |
case LBRACKET: |
2783 |
return arrayLiteral(); |
|
2784 |
case LBRACE: |
|
2785 |
return objectLiteral(); |
|
2786 |
case LPAREN: |
|
2787 |
next(); |
|
2788 |
||
37732 | 2789 |
if (isES6()) { |
2790 |
if (type == RPAREN) { |
|
2791 |
// () |
|
2792 |
nextOrEOL(); |
|
2793 |
expectDontAdvance(ARROW); |
|
2794 |
return new ExpressionList(primaryToken, finish, Collections.emptyList()); |
|
2795 |
} else if (type == ELLIPSIS) { |
|
2796 |
// (...rest) |
|
2797 |
final IdentNode restParam = formalParameterList(false).get(0); |
|
2798 |
expectDontAdvance(RPAREN); |
|
2799 |
nextOrEOL(); |
|
2800 |
expectDontAdvance(ARROW); |
|
2801 |
return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam)); |
|
2802 |
} |
|
2803 |
} |
|
2804 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2805 |
final Expression expression = expression(); |
16147 | 2806 |
|
2807 |
expect(RPAREN); |
|
2808 |
||
2809 |
return expression; |
|
33414 | 2810 |
case TEMPLATE: |
2811 |
case TEMPLATE_HEAD: |
|
2812 |
return templateLiteral(); |
|
16147 | 2813 |
|
2814 |
default: |
|
2815 |
// In this context some operator tokens mark the start of a literal. |
|
18870
aa4fceda2fba
8020437: Wrong handling of line numbers with multiline string literals
sundar
parents:
18867
diff
changeset
|
2816 |
if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { |
16147 | 2817 |
next(); |
2818 |
return getLiteral(); |
|
2819 |
} |
|
2820 |
if (isNonStrictModeIdent()) { |
|
2821 |
return getIdent(); |
|
2822 |
} |
|
2823 |
break; |
|
2824 |
} |
|
2825 |
||
2826 |
return null; |
|
2827 |
} |
|
2828 |
||
16211 | 2829 |
/** |
2830 |
* Convert execString to a call to $EXEC. |
|
2831 |
* |
|
2832 |
* @param primaryToken Original string token. |
|
2833 |
* @return callNode to $EXEC. |
|
2834 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2835 |
CallNode execString(final int primaryLine, final long primaryToken) { |
16211 | 2836 |
// Synthesize an ident to call $EXEC. |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
2837 |
final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); |
16211 | 2838 |
// Skip over EXECSTRING. |
2839 |
next(); |
|
2840 |
// Set up argument list for call. |
|
2841 |
// Skip beginning of edit string expression. |
|
2842 |
expect(LBRACE); |
|
2843 |
// Add the following expression to arguments. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2844 |
final List<Expression> arguments = Collections.singletonList(expression()); |
16211 | 2845 |
// Skip ending of edit string expression. |
2846 |
expect(RBRACE); |
|
2847 |
||
24751 | 2848 |
return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); |
16211 | 2849 |
} |
16147 | 2850 |
|
2851 |
/** |
|
2852 |
* ArrayLiteral : |
|
2853 |
* [ Elision? ] |
|
2854 |
* [ ElementList ] |
|
2855 |
* [ ElementList , Elision? ] |
|
2856 |
* [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] |
|
2857 |
* |
|
2858 |
* ElementList : Elision? AssignmentExpression |
|
2859 |
* ElementList , Elision? AssignmentExpression |
|
2860 |
* |
|
2861 |
* Elision : |
|
2862 |
* , |
|
2863 |
* Elision , |
|
2864 |
* |
|
2865 |
* See 12.1.4 |
|
2866 |
* JavaScript 1.8 |
|
2867 |
* |
|
2868 |
* Parse array literal. |
|
2869 |
* @return Expression node. |
|
2870 |
*/ |
|
38485
8c55199bc96b
8157241: Remove javac warnings of Nashorn "ant clean test"
sundar
parents:
37924
diff
changeset
|
2871 |
@SuppressWarnings("fallthrough") |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2872 |
private LiteralNode<Expression[]> arrayLiteral() { |
16147 | 2873 |
// Capture LBRACKET token. |
2874 |
final long arrayToken = token; |
|
2875 |
// LBRACKET tested in caller. |
|
2876 |
next(); |
|
2877 |
||
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2878 |
// Prepare to accumulate elements. |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2879 |
final List<Expression> elements = new ArrayList<>(); |
16147 | 2880 |
// Track elisions. |
2881 |
boolean elision = true; |
|
41425 | 2882 |
boolean hasSpread = false; |
37732 | 2883 |
loop: |
16147 | 2884 |
while (true) { |
37732 | 2885 |
long spreadToken = 0; |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
2886 |
switch (type) { |
16147 | 2887 |
case RBRACKET: |
2888 |
next(); |
|
2889 |
||
2890 |
break loop; |
|
2891 |
||
2892 |
case COMMARIGHT: |
|
2893 |
next(); |
|
2894 |
||
2895 |
// If no prior expression |
|
2896 |
if (elision) { |
|
2897 |
elements.add(null); |
|
2898 |
} |
|
2899 |
||
2900 |
elision = true; |
|
2901 |
||
2902 |
break; |
|
2903 |
||
37732 | 2904 |
case ELLIPSIS: |
2905 |
if (isES6()) { |
|
41425 | 2906 |
hasSpread = true; |
37732 | 2907 |
spreadToken = token; |
2908 |
next(); |
|
2909 |
} |
|
2910 |
// fall through |
|
2911 |
||
16147 | 2912 |
default: |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
2913 |
if (!elision) { |
17233 | 2914 |
throw error(AbstractParser.message("expected.comma", type.getNameOrType())); |
16147 | 2915 |
} |
37732 | 2916 |
|
16147 | 2917 |
// Add expression element. |
37732 | 2918 |
Expression expression = assignmentExpression(false); |
16147 | 2919 |
if (expression != null) { |
37732 | 2920 |
if (spreadToken != 0) { |
2921 |
expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression); |
|
2922 |
} |
|
16147 | 2923 |
elements.add(expression); |
2924 |
} else { |
|
2925 |
expect(RBRACKET); |
|
2926 |
} |
|
2927 |
||
2928 |
elision = false; |
|
2929 |
break; |
|
2930 |
} |
|
2931 |
} |
|
2932 |
||
41425 | 2933 |
return LiteralNode.newInstance(arrayToken, finish, elements, hasSpread, elision); |
16147 | 2934 |
} |
2935 |
||
2936 |
/** |
|
2937 |
* ObjectLiteral : |
|
2938 |
* { } |
|
2939 |
* { PropertyNameAndValueList } { PropertyNameAndValueList , } |
|
2940 |
* |
|
2941 |
* PropertyNameAndValueList : |
|
2942 |
* PropertyAssignment |
|
2943 |
* PropertyNameAndValueList , PropertyAssignment |
|
2944 |
* |
|
2945 |
* See 11.1.5 |
|
2946 |
* |
|
2947 |
* Parse an object literal. |
|
2948 |
* @return Expression node. |
|
2949 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
2950 |
private ObjectNode objectLiteral() { |
16147 | 2951 |
// Capture LBRACE token. |
2952 |
final long objectToken = token; |
|
2953 |
// LBRACE tested in caller. |
|
2954 |
next(); |
|
2955 |
||
2956 |
// Object context. |
|
2957 |
// Prepare to accumulate elements. |
|
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2958 |
final List<PropertyNode> elements = new ArrayList<>(); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2959 |
final Map<String, Integer> map = new HashMap<>(); |
16147 | 2960 |
|
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
2961 |
// Create a block for the object literal. |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2962 |
boolean commaSeen = true; |
37732 | 2963 |
loop: |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2964 |
while (true) { |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2965 |
switch (type) { |
16147 | 2966 |
case RBRACE: |
2967 |
next(); |
|
2968 |
break loop; |
|
2969 |
||
2970 |
case COMMARIGHT: |
|
18629
6b0b6aab4280
8019508: Comma handling in object literal parsing is wrong
sundar
parents:
18625
diff
changeset
|
2971 |
if (commaSeen) { |
6b0b6aab4280
8019508: Comma handling in object literal parsing is wrong
sundar
parents:
18625
diff
changeset
|
2972 |
throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); |
6b0b6aab4280
8019508: Comma handling in object literal parsing is wrong
sundar
parents:
18625
diff
changeset
|
2973 |
} |
16147 | 2974 |
next(); |
2975 |
commaSeen = true; |
|
2976 |
break; |
|
2977 |
||
2978 |
default: |
|
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
2979 |
if (!commaSeen) { |
17233 | 2980 |
throw error(AbstractParser.message("expected.comma", type.getNameOrType())); |
2981 |
} |
|
2982 |
||
2983 |
commaSeen = false; |
|
2984 |
// Get and add the next property. |
|
2985 |
final PropertyNode property = propertyAssignment(); |
|
37732 | 2986 |
|
2987 |
if (property.isComputed()) { |
|
2988 |
elements.add(property); |
|
2989 |
break; |
|
2990 |
} |
|
2991 |
||
17233 | 2992 |
final String key = property.getKeyName(); |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2993 |
final Integer existing = map.get(key); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2994 |
|
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2995 |
if (existing == null) { |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2996 |
map.put(key, elements.size()); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
2997 |
elements.add(property); |
17233 | 2998 |
break; |
2999 |
} |
|
3000 |
||
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3001 |
final PropertyNode existingProperty = elements.get(existing); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3002 |
|
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3003 |
// ECMA section 11.1.5 Object Initialiser |
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3004 |
// point # 4 on property assignment production |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3005 |
final Expression value = property.getValue(); |
17233 | 3006 |
final FunctionNode getter = property.getGetter(); |
3007 |
final FunctionNode setter = property.getSetter(); |
|
3008 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3009 |
final Expression prevValue = existingProperty.getValue(); |
17233 | 3010 |
final FunctionNode prevGetter = existingProperty.getGetter(); |
3011 |
final FunctionNode prevSetter = existingProperty.getSetter(); |
|
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3012 |
|
37732 | 3013 |
if (!isES6()) { |
3014 |
checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter); |
|
3015 |
} else { |
|
3016 |
if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() && |
|
3017 |
existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) { |
|
3018 |
throw error(AbstractParser.message("multiple.proto.key"), property.getToken()); |
|
16147 | 3019 |
} |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3020 |
} |
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3021 |
|
37732 | 3022 |
if (value != null || prevValue != null) { |
3023 |
map.put(key, elements.size()); |
|
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3024 |
elements.add(property); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3025 |
} else if (getter != null) { |
37732 | 3026 |
assert prevGetter != null || prevSetter != null; |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3027 |
elements.set(existing, existingProperty.setGetter(getter)); |
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3028 |
} else if (setter != null) { |
37732 | 3029 |
assert prevGetter != null || prevSetter != null; |
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3030 |
elements.set(existing, existingProperty.setSetter(setter)); |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16262
diff
changeset
|
3031 |
} |
17233 | 3032 |
break; |
16147 | 3033 |
} |
3034 |
} |
|
3035 |
||
18877
6d75ba520886
8020354: Object literal property initialization is not done in source order
hannesw
parents:
18870
diff
changeset
|
3036 |
return new ObjectNode(objectToken, finish, elements); |
16147 | 3037 |
} |
3038 |
||
37732 | 3039 |
private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { |
3040 |
// ECMA 11.1.5 strict mode restrictions |
|
3041 |
if (isStrictMode && value != null && prevValue != null) { |
|
3042 |
throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3043 |
} |
|
3044 |
||
3045 |
final boolean isPrevAccessor = prevGetter != null || prevSetter != null; |
|
3046 |
final boolean isAccessor = getter != null || setter != null; |
|
3047 |
||
3048 |
// data property redefined as accessor property |
|
3049 |
if (prevValue != null && isAccessor) { |
|
3050 |
throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3051 |
} |
|
3052 |
||
3053 |
// accessor property redefined as data |
|
3054 |
if (isPrevAccessor && value != null) { |
|
3055 |
throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3056 |
} |
|
3057 |
||
3058 |
if (isAccessor && isPrevAccessor) { |
|
3059 |
if (getter != null && prevGetter != null || |
|
3060 |
setter != null && prevSetter != null) { |
|
3061 |
throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3062 |
} |
|
3063 |
} |
|
3064 |
} |
|
3065 |
||
16147 | 3066 |
/** |
37732 | 3067 |
* LiteralPropertyName : |
16147 | 3068 |
* IdentifierName |
3069 |
* StringLiteral |
|
3070 |
* NumericLiteral |
|
3071 |
* |
|
3072 |
* @return PropertyName node |
|
3073 |
*/ |
|
3074 |
@SuppressWarnings("fallthrough") |
|
37732 | 3075 |
private PropertyKey literalPropertyName() { |
16147 | 3076 |
switch (type) { |
3077 |
case IDENT: |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3078 |
return getIdent().setIsPropertyName(); |
32444 | 3079 |
case OCTAL_LEGACY: |
16147 | 3080 |
if (isStrictMode) { |
17233 | 3081 |
throw error(AbstractParser.message("strict.no.octal"), token); |
16147 | 3082 |
} |
3083 |
case STRING: |
|
3084 |
case ESCSTRING: |
|
3085 |
case DECIMAL: |
|
3086 |
case HEXADECIMAL: |
|
32444 | 3087 |
case OCTAL: |
3088 |
case BINARY_NUMBER: |
|
16147 | 3089 |
case FLOATING: |
3090 |
return getLiteral(); |
|
3091 |
default: |
|
19883
aae0838ac6ee
8024255: When a keyword is used as object property name, the property can not be deleted
sundar
parents:
19472
diff
changeset
|
3092 |
return getIdentifierName().setIsPropertyName(); |
16147 | 3093 |
} |
3094 |
} |
|
3095 |
||
3096 |
/** |
|
37732 | 3097 |
* ComputedPropertyName : |
3098 |
* AssignmentExpression |
|
3099 |
* |
|
3100 |
* @return PropertyName node |
|
3101 |
*/ |
|
3102 |
private Expression computedPropertyName() { |
|
3103 |
expect(LBRACKET); |
|
41422 | 3104 |
final Expression expression = assignmentExpression(false); |
37732 | 3105 |
expect(RBRACKET); |
3106 |
return expression; |
|
3107 |
} |
|
3108 |
||
3109 |
/** |
|
3110 |
* PropertyName : |
|
3111 |
* LiteralPropertyName |
|
3112 |
* ComputedPropertyName |
|
3113 |
* |
|
3114 |
* @return PropertyName node |
|
3115 |
*/ |
|
3116 |
private Expression propertyName() { |
|
3117 |
if (type == LBRACKET && isES6()) { |
|
3118 |
return computedPropertyName(); |
|
3119 |
} else { |
|
3120 |
return (Expression)literalPropertyName(); |
|
3121 |
} |
|
3122 |
} |
|
3123 |
||
3124 |
/** |
|
16147 | 3125 |
* PropertyAssignment : |
3126 |
* PropertyName : AssignmentExpression |
|
3127 |
* get PropertyName ( ) { FunctionBody } |
|
3128 |
* set PropertyName ( PropertySetParameterList ) { FunctionBody } |
|
3129 |
* |
|
3130 |
* PropertySetParameterList : |
|
3131 |
* Identifier |
|
3132 |
* |
|
3133 |
* PropertyName : |
|
3134 |
* IdentifierName |
|
3135 |
* StringLiteral |
|
3136 |
* NumericLiteral |
|
3137 |
* |
|
3138 |
* See 11.1.5 |
|
3139 |
* |
|
3140 |
* Parse an object literal property. |
|
3141 |
* @return Property or reference node. |
|
3142 |
*/ |
|
3143 |
private PropertyNode propertyAssignment() { |
|
3144 |
// Capture firstToken. |
|
3145 |
final long propertyToken = token; |
|
24719 | 3146 |
final int functionLine = line; |
3147 |
||
37732 | 3148 |
final Expression propertyName; |
3149 |
final boolean isIdentifier; |
|
3150 |
||
3151 |
boolean generator = false; |
|
3152 |
if (type == MUL && isES6()) { |
|
3153 |
generator = true; |
|
3154 |
next(); |
|
3155 |
} |
|
3156 |
||
3157 |
final boolean computed = type == LBRACKET; |
|
16147 | 3158 |
if (type == IDENT) { |
3159 |
// Get IDENT. |
|
3160 |
final String ident = (String)expectValue(IDENT); |
|
3161 |
||
37732 | 3162 |
if (type != COLON && (type != LPAREN || !isES6())) { |
20938
e92d8249f60c
8026302: source representation of getter and setter methods is wrong
sundar
parents:
20934
diff
changeset
|
3163 |
final long getSetToken = propertyToken; |
16147 | 3164 |
|
3165 |
switch (ident) { |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
3166 |
case GET_NAME: |
24719 | 3167 |
final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); |
37732 | 3168 |
return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed); |
16147 | 3169 |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
3170 |
case SET_NAME: |
24719 | 3171 |
final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); |
37732 | 3172 |
return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed); |
16147 | 3173 |
default: |
3174 |
break; |
|
3175 |
} |
|
3176 |
} |
|
3177 |
||
37732 | 3178 |
isIdentifier = true; |
3179 |
IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); |
|
3180 |
if (type == COLON && ident.equals("__proto__")) { |
|
3181 |
identNode = identNode.setIsProtoPropertyName(); |
|
3182 |
} |
|
3183 |
propertyName = identNode; |
|
16147 | 3184 |
} else { |
37732 | 3185 |
isIdentifier = isNonStrictModeIdent(); |
16147 | 3186 |
propertyName = propertyName(); |
3187 |
} |
|
3188 |
||
37732 | 3189 |
Expression propertyValue; |
3190 |
||
3191 |
if (generator) { |
|
3192 |
expectDontAdvance(LPAREN); |
|
24719 | 3193 |
} |
37732 | 3194 |
|
3195 |
if (type == LPAREN && isES6()) { |
|
3196 |
propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode; |
|
3197 |
} else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) { |
|
3198 |
propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName()); |
|
3199 |
if (type == ASSIGN && isES6()) { |
|
3200 |
// TODO if not destructuring, this is a SyntaxError |
|
3201 |
final long assignToken = token; |
|
3202 |
next(); |
|
3203 |
final Expression rhs = assignmentExpression(false); |
|
3204 |
propertyValue = verifyAssignment(assignToken, propertyValue, rhs); |
|
3205 |
} |
|
3206 |
} else { |
|
3207 |
expect(COLON); |
|
3208 |
||
3209 |
defaultNames.push(propertyName); |
|
3210 |
try { |
|
3211 |
propertyValue = assignmentExpression(false); |
|
3212 |
} finally { |
|
3213 |
defaultNames.pop(); |
|
3214 |
} |
|
3215 |
} |
|
3216 |
||
3217 |
return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed); |
|
24719 | 3218 |
} |
3219 |
||
3220 |
private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { |
|
37732 | 3221 |
return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); |
3222 |
} |
|
3223 |
||
3224 |
private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) { |
|
3225 |
final boolean computed = type == LBRACKET; |
|
3226 |
final Expression propertyName = propertyName(); |
|
3227 |
final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); |
|
3228 |
final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName)); |
|
24719 | 3229 |
expect(LPAREN); |
3230 |
expect(RPAREN); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3231 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3232 |
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); |
37732 | 3233 |
functionNode.setFlag(flags); |
3234 |
if (computed) { |
|
3235 |
functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
3236 |
} |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3237 |
lc.push(functionNode); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3238 |
|
27819
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3239 |
Block functionBody; |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3240 |
|
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3241 |
|
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3242 |
try { |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3243 |
functionBody = functionBody(functionNode); |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3244 |
} finally { |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3245 |
lc.pop(functionNode); |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3246 |
} |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3247 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3248 |
final FunctionNode function = createFunctionNode( |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3249 |
functionNode, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3250 |
getSetToken, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3251 |
getNameNode, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3252 |
Collections.<IdentNode>emptyList(), |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3253 |
FunctionNode.Kind.GETTER, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3254 |
functionLine, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3255 |
functionBody); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3256 |
|
37732 | 3257 |
return new PropertyFunction(propertyName, function, computed); |
24719 | 3258 |
} |
3259 |
||
3260 |
private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { |
|
37732 | 3261 |
return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); |
3262 |
} |
|
3263 |
||
3264 |
private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) { |
|
3265 |
final boolean computed = type == LBRACKET; |
|
3266 |
final Expression propertyName = propertyName(); |
|
3267 |
final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); |
|
3268 |
final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName)); |
|
24719 | 3269 |
expect(LPAREN); |
3270 |
// be sloppy and allow missing setter parameter even though |
|
3271 |
// spec does not permit it! |
|
3272 |
final IdentNode argIdent; |
|
37732 | 3273 |
if (isBindingIdentifier()) { |
24719 | 3274 |
argIdent = getIdent(); |
37732 | 3275 |
verifyIdent(argIdent, "setter argument"); |
24719 | 3276 |
} else { |
3277 |
argIdent = null; |
|
3278 |
} |
|
3279 |
expect(RPAREN); |
|
3280 |
final List<IdentNode> parameters = new ArrayList<>(); |
|
3281 |
if (argIdent != null) { |
|
3282 |
parameters.add(argIdent); |
|
3283 |
} |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3284 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3285 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3286 |
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); |
37732 | 3287 |
functionNode.setFlag(flags); |
3288 |
if (computed) { |
|
3289 |
functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
3290 |
} |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3291 |
lc.push(functionNode); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3292 |
|
27819
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3293 |
Block functionBody; |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3294 |
try { |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3295 |
functionBody = functionBody(functionNode); |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3296 |
} finally { |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3297 |
lc.pop(functionNode); |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3298 |
} |
74baae50e5cd
8066238: AssertionError in parser when syntax errors appeared in non finished Blocks
lagergren
parents:
27817
diff
changeset
|
3299 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3300 |
|
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3301 |
final FunctionNode function = createFunctionNode( |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3302 |
functionNode, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3303 |
getSetToken, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3304 |
setNameNode, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3305 |
parameters, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3306 |
FunctionNode.Kind.SETTER, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3307 |
functionLine, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3308 |
functionBody); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3309 |
|
37732 | 3310 |
return new PropertyFunction(propertyName, function, computed); |
3311 |
} |
|
3312 |
||
41422 | 3313 |
private PropertyFunction propertyMethodFunction(final Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, final boolean computed) { |
37732 | 3314 |
final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false); |
3315 |
final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName); |
|
3316 |
||
41422 | 3317 |
final FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; |
37732 | 3318 |
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null); |
3319 |
functionNode.setFlag(flags); |
|
3320 |
if (computed) { |
|
3321 |
functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
3322 |
} |
|
3323 |
lc.push(functionNode); |
|
3324 |
||
3325 |
try { |
|
3326 |
final ParserContextBlockNode parameterBlock = newBlock(); |
|
3327 |
final List<IdentNode> parameters; |
|
3328 |
try { |
|
3329 |
expect(LPAREN); |
|
3330 |
parameters = formalParameterList(generator); |
|
3331 |
functionNode.setParameters(parameters); |
|
3332 |
expect(RPAREN); |
|
3333 |
} finally { |
|
3334 |
restoreBlock(parameterBlock); |
|
3335 |
} |
|
3336 |
||
3337 |
Block functionBody = functionBody(functionNode); |
|
3338 |
||
3339 |
functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
|
3340 |
||
3341 |
final FunctionNode function = createFunctionNode( |
|
3342 |
functionNode, |
|
3343 |
methodToken, |
|
3344 |
methodNameNode, |
|
3345 |
parameters, |
|
3346 |
functionKind, |
|
3347 |
methodLine, |
|
3348 |
functionBody); |
|
3349 |
return new PropertyFunction(key, function, computed); |
|
3350 |
} finally { |
|
3351 |
lc.pop(functionNode); |
|
3352 |
} |
|
24719 | 3353 |
} |
3354 |
||
3355 |
private static class PropertyFunction { |
|
37732 | 3356 |
final Expression key; |
24719 | 3357 |
final FunctionNode functionNode; |
37732 | 3358 |
final boolean computed; |
3359 |
||
3360 |
PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) { |
|
3361 |
this.key = key; |
|
24719 | 3362 |
this.functionNode = function; |
37732 | 3363 |
this.computed = computed; |
24719 | 3364 |
} |
17233 | 3365 |
} |
3366 |
||
16147 | 3367 |
/** |
3368 |
* LeftHandSideExpression : |
|
3369 |
* NewExpression |
|
3370 |
* CallExpression |
|
3371 |
* |
|
3372 |
* CallExpression : |
|
3373 |
* MemberExpression Arguments |
|
37732 | 3374 |
* SuperCall |
16147 | 3375 |
* CallExpression Arguments |
3376 |
* CallExpression [ Expression ] |
|
3377 |
* CallExpression . IdentifierName |
|
37732 | 3378 |
* |
3379 |
* SuperCall : |
|
3380 |
* super Arguments |
|
16147 | 3381 |
* |
37732 | 3382 |
* See 11.2 |
3383 |
* |
|
3384 |
* Parse left hand side expression. |
|
16147 | 3385 |
* @return Expression node. |
3386 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3387 |
private Expression leftHandSideExpression() { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
3388 |
int callLine = line; |
16147 | 3389 |
long callToken = token; |
3390 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3391 |
Expression lhs = memberExpression(); |
16147 | 3392 |
|
3393 |
if (type == LPAREN) { |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3394 |
final List<Expression> arguments = optimizeList(argumentList()); |
16147 | 3395 |
|
3396 |
// Catch special functions. |
|
3397 |
if (lhs instanceof IdentNode) { |
|
3398 |
detectSpecialFunction((IdentNode)lhs); |
|
3399 |
} |
|
3400 |
||
24751 | 3401 |
lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
16147 | 3402 |
} |
3403 |
||
37732 | 3404 |
loop: |
16147 | 3405 |
while (true) { |
3406 |
// Capture token. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
3407 |
callLine = line; |
16147 | 3408 |
callToken = token; |
3409 |
||
3410 |
switch (type) { |
|
33414 | 3411 |
case LPAREN: { |
16147 | 3412 |
// Get NEW or FUNCTION arguments. |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3413 |
final List<Expression> arguments = optimizeList(argumentList()); |
16147 | 3414 |
|
3415 |
// Create call node. |
|
24751 | 3416 |
lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
16147 | 3417 |
|
3418 |
break; |
|
33414 | 3419 |
} |
3420 |
case LBRACKET: { |
|
16147 | 3421 |
next(); |
3422 |
||
3423 |
// Get array index. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3424 |
final Expression rhs = expression(); |
16147 | 3425 |
|
3426 |
expect(RBRACKET); |
|
3427 |
||
3428 |
// Create indexing node. |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
3429 |
lhs = new IndexNode(callToken, finish, lhs, rhs); |
16147 | 3430 |
|
3431 |
break; |
|
33414 | 3432 |
} |
3433 |
case PERIOD: { |
|
16147 | 3434 |
next(); |
3435 |
||
3436 |
final IdentNode property = getIdentifierName(); |
|
3437 |
||
3438 |
// Create property access node. |
|
24751 | 3439 |
lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
16147 | 3440 |
|
3441 |
break; |
|
33414 | 3442 |
} |
3443 |
case TEMPLATE: |
|
3444 |
case TEMPLATE_HEAD: { |
|
3445 |
// tagged template literal |
|
3446 |
final List<Expression> arguments = templateLiteralArgumentList(); |
|
3447 |
||
37732 | 3448 |
// Create call node. |
33414 | 3449 |
lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
3450 |
||
3451 |
break; |
|
3452 |
} |
|
16147 | 3453 |
default: |
3454 |
break loop; |
|
3455 |
} |
|
3456 |
} |
|
3457 |
||
3458 |
return lhs; |
|
3459 |
} |
|
3460 |
||
3461 |
/** |
|
3462 |
* NewExpression : |
|
3463 |
* MemberExpression |
|
3464 |
* new NewExpression |
|
3465 |
* |
|
3466 |
* See 11.2 |
|
3467 |
* |
|
3468 |
* Parse new expression. |
|
3469 |
* @return Expression node. |
|
3470 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3471 |
private Expression newExpression() { |
16147 | 3472 |
final long newToken = token; |
3473 |
// NEW is tested in caller. |
|
3474 |
next(); |
|
3475 |
||
37732 | 3476 |
if (type == PERIOD && isES6()) { |
3477 |
next(); |
|
3478 |
if (type == IDENT && "target".equals(getValue())) { |
|
3479 |
if (lc.getCurrentFunction().isProgram()) { |
|
3480 |
throw error(AbstractParser.message("new.target.in.function"), token); |
|
3481 |
} |
|
3482 |
next(); |
|
3483 |
markNewTarget(lc); |
|
3484 |
return new IdentNode(newToken, finish, "new.target"); |
|
3485 |
} else { |
|
3486 |
throw error(AbstractParser.message("expected.target"), token); |
|
3487 |
} |
|
3488 |
} |
|
3489 |
||
16147 | 3490 |
// Get function base. |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
3491 |
final int callLine = line; |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3492 |
final Expression constructor = memberExpression(); |
16147 | 3493 |
if (constructor == null) { |
3494 |
return null; |
|
3495 |
} |
|
3496 |
// Get arguments. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3497 |
ArrayList<Expression> arguments; |
16147 | 3498 |
|
3499 |
// Allow for missing arguments. |
|
3500 |
if (type == LPAREN) { |
|
3501 |
arguments = argumentList(); |
|
3502 |
} else { |
|
3503 |
arguments = new ArrayList<>(); |
|
3504 |
} |
|
3505 |
||
16196
58f6f046bb5e
8006983: Introduce a command line option to switch off syntactic extensions of nashorn
sundar
parents:
16191
diff
changeset
|
3506 |
// Nashorn extension: This is to support the following interface implementation |
58f6f046bb5e
8006983: Introduce a command line option to switch off syntactic extensions of nashorn
sundar
parents:
16191
diff
changeset
|
3507 |
// syntax: |
16147 | 3508 |
// |
3509 |
// var r = new java.lang.Runnable() { |
|
3510 |
// run: function() { println("run"); } |
|
3511 |
// }; |
|
3512 |
// |
|
32534
b3ec7f3b3c2a
8136349: Typos patch for nashorn sources submitted on Sep 10, 2015
sundar
parents:
32444
diff
changeset
|
3513 |
// The object literal following the "new Constructor()" expression |
16147 | 3514 |
// is passed as an additional (last) argument to the constructor. |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
3515 |
if (!env._no_syntax_extensions && type == LBRACE) { |
16147 | 3516 |
arguments.add(objectLiteral()); |
3517 |
} |
|
3518 |
||
24751 | 3519 |
final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
3520 |
|
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
3521 |
return new UnaryNode(newToken, callNode); |
16147 | 3522 |
} |
3523 |
||
3524 |
/** |
|
3525 |
* MemberExpression : |
|
3526 |
* PrimaryExpression |
|
37732 | 3527 |
* FunctionExpression |
3528 |
* ClassExpression |
|
3529 |
* GeneratorExpression |
|
16147 | 3530 |
* MemberExpression [ Expression ] |
3531 |
* MemberExpression . IdentifierName |
|
33414 | 3532 |
* MemberExpression TemplateLiteral |
37732 | 3533 |
* SuperProperty |
3534 |
* MetaProperty |
|
16147 | 3535 |
* new MemberExpression Arguments |
3536 |
* |
|
37732 | 3537 |
* SuperProperty : |
3538 |
* super [ Expression ] |
|
3539 |
* super . IdentifierName |
|
3540 |
* |
|
3541 |
* MetaProperty : |
|
3542 |
* NewTarget |
|
3543 |
* |
|
3544 |
* Parse member expression. |
|
16147 | 3545 |
* @return Expression node. |
3546 |
*/ |
|
37732 | 3547 |
@SuppressWarnings("fallthrough") |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3548 |
private Expression memberExpression() { |
16147 | 3549 |
// Prepare to build operation. |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3550 |
Expression lhs; |
37732 | 3551 |
boolean isSuper = false; |
16147 | 3552 |
|
3553 |
switch (type) { |
|
3554 |
case NEW: |
|
24751 | 3555 |
// Get new expression. |
16147 | 3556 |
lhs = newExpression(); |
3557 |
break; |
|
3558 |
||
3559 |
case FUNCTION: |
|
3560 |
// Get function expression. |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
3561 |
lhs = functionExpression(false, false); |
16147 | 3562 |
break; |
3563 |
||
37732 | 3564 |
case CLASS: |
3565 |
if (isES6()) { |
|
3566 |
lhs = classExpression(false); |
|
3567 |
break; |
|
3568 |
} else { |
|
3569 |
// fall through |
|
3570 |
} |
|
3571 |
||
3572 |
case SUPER: |
|
3573 |
if (isES6()) { |
|
3574 |
final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction(); |
|
3575 |
if (currentFunction.isMethod()) { |
|
41422 | 3576 |
final long identToken = Token.recast(token, IDENT); |
37732 | 3577 |
next(); |
3578 |
lhs = createIdentNode(identToken, finish, SUPER.getName()); |
|
3579 |
||
3580 |
switch (type) { |
|
3581 |
case LBRACKET: |
|
3582 |
case PERIOD: |
|
3583 |
getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER); |
|
3584 |
isSuper = true; |
|
3585 |
break; |
|
3586 |
case LPAREN: |
|
3587 |
if (currentFunction.isSubclassConstructor()) { |
|
3588 |
lhs = ((IdentNode)lhs).setIsDirectSuper(); |
|
3589 |
break; |
|
3590 |
} else { |
|
3591 |
// fall through to throw error |
|
3592 |
} |
|
3593 |
default: |
|
3594 |
throw error(AbstractParser.message("invalid.super"), identToken); |
|
3595 |
} |
|
3596 |
break; |
|
3597 |
} else { |
|
3598 |
// fall through |
|
3599 |
} |
|
3600 |
} else { |
|
3601 |
// fall through |
|
3602 |
} |
|
3603 |
||
16147 | 3604 |
default: |
3605 |
// Get primary expression. |
|
3606 |
lhs = primaryExpression(); |
|
3607 |
break; |
|
3608 |
} |
|
3609 |
||
37732 | 3610 |
loop: |
16147 | 3611 |
while (true) { |
3612 |
// Capture token. |
|
3613 |
final long callToken = token; |
|
3614 |
||
3615 |
switch (type) { |
|
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
3616 |
case LBRACKET: { |
16147 | 3617 |
next(); |
3618 |
||
3619 |
// Get array index. |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3620 |
final Expression index = expression(); |
16147 | 3621 |
|
3622 |
expect(RBRACKET); |
|
3623 |
||
3624 |
// Create indexing node. |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
3625 |
lhs = new IndexNode(callToken, finish, lhs, index); |
16147 | 3626 |
|
37732 | 3627 |
if (isSuper) { |
3628 |
isSuper = false; |
|
3629 |
lhs = ((BaseNode) lhs).setIsSuper(); |
|
3630 |
} |
|
3631 |
||
16147 | 3632 |
break; |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
3633 |
} |
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
3634 |
case PERIOD: { |
16147 | 3635 |
if (lhs == null) { |
17233 | 3636 |
throw error(AbstractParser.message("expected.operand", type.getNameOrType())); |
16147 | 3637 |
} |
3638 |
||
3639 |
next(); |
|
3640 |
||
3641 |
final IdentNode property = getIdentifierName(); |
|
3642 |
||
3643 |
// Create property access node. |
|
24751 | 3644 |
lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
16147 | 3645 |
|
37732 | 3646 |
if (isSuper) { |
3647 |
isSuper = false; |
|
3648 |
lhs = ((BaseNode) lhs).setIsSuper(); |
|
3649 |
} |
|
3650 |
||
16147 | 3651 |
break; |
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
3652 |
} |
33414 | 3653 |
case TEMPLATE: |
3654 |
case TEMPLATE_HEAD: { |
|
3655 |
// tagged template literal |
|
3656 |
final int callLine = line; |
|
3657 |
final List<Expression> arguments = templateLiteralArgumentList(); |
|
3658 |
||
3659 |
lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
|
3660 |
||
3661 |
break; |
|
3662 |
} |
|
16147 | 3663 |
default: |
3664 |
break loop; |
|
3665 |
} |
|
3666 |
} |
|
3667 |
||
3668 |
return lhs; |
|
3669 |
} |
|
3670 |
||
3671 |
/** |
|
3672 |
* Arguments : |
|
3673 |
* ( ) |
|
3674 |
* ( ArgumentList ) |
|
3675 |
* |
|
3676 |
* ArgumentList : |
|
3677 |
* AssignmentExpression |
|
37732 | 3678 |
* ... AssignmentExpression |
16147 | 3679 |
* ArgumentList , AssignmentExpression |
37732 | 3680 |
* ArgumentList , ... AssignmentExpression |
16147 | 3681 |
* |
3682 |
* See 11.2 |
|
3683 |
* |
|
3684 |
* Parse function call arguments. |
|
3685 |
* @return Argument list. |
|
3686 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3687 |
private ArrayList<Expression> argumentList() { |
16147 | 3688 |
// Prepare to accumulate list of arguments. |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3689 |
final ArrayList<Expression> nodeList = new ArrayList<>(); |
16147 | 3690 |
// LPAREN tested in caller. |
3691 |
next(); |
|
3692 |
||
3693 |
// Track commas. |
|
3694 |
boolean first = true; |
|
3695 |
||
3696 |
while (type != RPAREN) { |
|
3697 |
// Comma prior to every argument except the first. |
|
3698 |
if (!first) { |
|
3699 |
expect(COMMARIGHT); |
|
3700 |
} else { |
|
3701 |
first = false; |
|
3702 |
} |
|
3703 |
||
37732 | 3704 |
long spreadToken = 0; |
3705 |
if (type == ELLIPSIS && isES6()) { |
|
3706 |
spreadToken = token; |
|
3707 |
next(); |
|
3708 |
} |
|
3709 |
||
16147 | 3710 |
// Get argument expression. |
37732 | 3711 |
Expression expression = assignmentExpression(false); |
3712 |
if (spreadToken != 0) { |
|
3713 |
expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression); |
|
3714 |
} |
|
3715 |
nodeList.add(expression); |
|
16147 | 3716 |
} |
3717 |
||
3718 |
expect(RPAREN); |
|
3719 |
return nodeList; |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3720 |
} |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3721 |
|
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
3722 |
private static <T> List<T> optimizeList(final ArrayList<T> list) { |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3723 |
switch(list.size()) { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3724 |
case 0: { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3725 |
return Collections.emptyList(); |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3726 |
} |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3727 |
case 1: { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3728 |
return Collections.singletonList(list.get(0)); |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3729 |
} |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3730 |
default: { |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3731 |
list.trimToSize(); |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3732 |
return list; |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3733 |
} |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3734 |
} |
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3735 |
} |
16147 | 3736 |
|
3737 |
/** |
|
3738 |
* FunctionDeclaration : |
|
3739 |
* function Identifier ( FormalParameterList? ) { FunctionBody } |
|
3740 |
* |
|
3741 |
* FunctionExpression : |
|
3742 |
* function Identifier? ( FormalParameterList? ) { FunctionBody } |
|
3743 |
* |
|
3744 |
* See 13 |
|
3745 |
* |
|
3746 |
* Parse function declaration. |
|
3747 |
* @param isStatement True if for is a statement. |
|
3748 |
* |
|
3749 |
* @return Expression node. |
|
3750 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
3751 |
private Expression functionExpression(final boolean isStatement, final boolean topLevel) { |
16147 | 3752 |
final long functionToken = token; |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
3753 |
final int functionLine = line; |
16147 | 3754 |
// FUNCTION is tested in caller. |
37732 | 3755 |
assert type == FUNCTION; |
16147 | 3756 |
next(); |
3757 |
||
37732 | 3758 |
boolean generator = false; |
3759 |
if (type == MUL && isES6()) { |
|
3760 |
generator = true; |
|
3761 |
next(); |
|
3762 |
} |
|
3763 |
||
16147 | 3764 |
IdentNode name = null; |
3765 |
||
37732 | 3766 |
if (isBindingIdentifier()) { |
3767 |
if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) { |
|
3768 |
// 12.1.1 Early SyntaxError if: |
|
3769 |
// GeneratorExpression with BindingIdentifier yield |
|
3770 |
// HoistableDeclaration with BindingIdentifier yield in generator function body |
|
3771 |
expect(IDENT); |
|
3772 |
} |
|
16147 | 3773 |
name = getIdent(); |
3774 |
verifyStrictIdent(name, "function name"); |
|
16196
58f6f046bb5e
8006983: Introduce a command line option to switch off syntactic extensions of nashorn
sundar
parents:
16191
diff
changeset
|
3775 |
} else if (isStatement) { |
31095
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3776 |
// Nashorn extension: anonymous function statements. |
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3777 |
// Do not allow anonymous function statement if extensions |
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3778 |
// are now allowed. But if we are reparsing then anon function |
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3779 |
// statement is possible - because it was used as function |
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3780 |
// expression in surrounding code. |
790fc3d576f9
8085802: Nashorn -nse option causes parse error on anonymous function definition
sundar
parents:
30392
diff
changeset
|
3781 |
if (env._no_syntax_extensions && reparsedFunction == null) { |
16196
58f6f046bb5e
8006983: Introduce a command line option to switch off syntactic extensions of nashorn
sundar
parents:
16191
diff
changeset
|
3782 |
expect(IDENT); |
58f6f046bb5e
8006983: Introduce a command line option to switch off syntactic extensions of nashorn
sundar
parents:
16191
diff
changeset
|
3783 |
} |
16147 | 3784 |
} |
3785 |
||
3786 |
// name is null, generate anonymous name |
|
3787 |
boolean isAnonymous = false; |
|
3788 |
if (name == null) { |
|
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3789 |
final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
3790 |
name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); |
16147 | 3791 |
isAnonymous = true; |
3792 |
} |
|
3793 |
||
41422 | 3794 |
final FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; |
37732 | 3795 |
List<IdentNode> parameters = Collections.emptyList(); |
3796 |
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3797 |
lc.push(functionNode); |
37732 | 3798 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3799 |
Block functionBody = null; |
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3800 |
// Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3801 |
// If we didn't hide the current default name, then the innermost anonymous function would receive "x3". |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3802 |
hideDefaultName(); |
37732 | 3803 |
try { |
3804 |
final ParserContextBlockNode parameterBlock = newBlock(); |
|
3805 |
try { |
|
3806 |
expect(LPAREN); |
|
3807 |
parameters = formalParameterList(generator); |
|
3808 |
functionNode.setParameters(parameters); |
|
3809 |
expect(RPAREN); |
|
3810 |
} finally { |
|
3811 |
restoreBlock(parameterBlock); |
|
3812 |
} |
|
3813 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3814 |
functionBody = functionBody(functionNode); |
37732 | 3815 |
|
3816 |
functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3817 |
} finally { |
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3818 |
defaultNames.pop(); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3819 |
lc.pop(functionNode); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3820 |
} |
16147 | 3821 |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
3822 |
if (isStatement) { |
37732 | 3823 |
if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3824 |
functionNode.setFlag(FunctionNode.IS_DECLARED); |
17257
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3825 |
} else if (isStrictMode) { |
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3826 |
throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); |
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3827 |
} else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { |
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3828 |
throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); |
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3829 |
} else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { |
a2232050cd8f
8008814: Configurable ignore/warning/error behavior for function declaration as statement
attila
parents:
17255
diff
changeset
|
3830 |
warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
3831 |
} |
19898
58c39862aa3f
8024846: keep separate internal arguments variable
attila
parents:
19883
diff
changeset
|
3832 |
if (isArguments(name)) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3833 |
lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3834 |
} |
16147 | 3835 |
} |
3836 |
||
3837 |
if (isAnonymous) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3838 |
functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
16147 | 3839 |
} |
3840 |
||
37732 | 3841 |
verifyParameterList(parameters, functionNode); |
16147 | 3842 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3843 |
final FunctionNode function = createFunctionNode( |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3844 |
functionNode, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3845 |
functionToken, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3846 |
name, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3847 |
parameters, |
37732 | 3848 |
functionKind, |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3849 |
functionLine, |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3850 |
functionBody); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3851 |
|
16147 | 3852 |
if (isStatement) { |
31485
be1acaee8e9e
8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
sundar
parents:
31095
diff
changeset
|
3853 |
if (isAnonymous) { |
be1acaee8e9e
8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
sundar
parents:
31095
diff
changeset
|
3854 |
appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function)); |
be1acaee8e9e
8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
sundar
parents:
31095
diff
changeset
|
3855 |
return function; |
be1acaee8e9e
8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
sundar
parents:
31095
diff
changeset
|
3856 |
} |
be1acaee8e9e
8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
sundar
parents:
31095
diff
changeset
|
3857 |
|
27817
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
3858 |
// mark ES6 block functions as lexically scoped |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
3859 |
final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; |
56f6161c3e55
8057980: let & const: remaining issues with lexical scoping
hannesw
parents:
27814
diff
changeset
|
3860 |
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); |
17233 | 3861 |
if (topLevel) { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
3862 |
functionDeclarations.add(varNode); |
26377
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
3863 |
} else if (useBlockScope()) { |
028dad61662f
8051889: Implement block scoping in symbol assignment and scope computation
hannesw
parents:
26246
diff
changeset
|
3864 |
prependStatement(varNode); // Hoist to beginning of current block |
16191
7dd981da8e11
8006755: Functions inside with statements dont get correct scope
sundar
parents:
16187
diff
changeset
|
3865 |
} else { |
17233 | 3866 |
appendStatement(varNode); |
16191
7dd981da8e11
8006755: Functions inside with statements dont get correct scope
sundar
parents:
16187
diff
changeset
|
3867 |
} |
16147 | 3868 |
} |
3869 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
3870 |
return function; |
16147 | 3871 |
} |
3872 |
||
37732 | 3873 |
private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) { |
3874 |
final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding(); |
|
3875 |
if (duplicateParameter != null) { |
|
3876 |
if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) { |
|
3877 |
throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken()); |
|
3878 |
} |
|
3879 |
||
3880 |
final int arity = parameters.size(); |
|
3881 |
final HashSet<String> parametersSet = new HashSet<>(arity); |
|
3882 |
||
3883 |
for (int i = arity - 1; i >= 0; i--) { |
|
3884 |
final IdentNode parameter = parameters.get(i); |
|
3885 |
String parameterName = parameter.getName(); |
|
3886 |
||
3887 |
if (parametersSet.contains(parameterName)) { |
|
3888 |
// redefinition of parameter name, rename in non-strict mode |
|
3889 |
parameterName = functionNode.uniqueName(parameterName); |
|
3890 |
final long parameterToken = parameter.getToken(); |
|
3891 |
parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); |
|
3892 |
} |
|
3893 |
parametersSet.add(parameterName); |
|
3894 |
} |
|
3895 |
} |
|
3896 |
} |
|
3897 |
||
41422 | 3898 |
private static Block maybeWrapBodyInParameterBlock(final Block functionBody, final ParserContextBlockNode parameterBlock) { |
37732 | 3899 |
assert functionBody.isFunctionBody(); |
3900 |
if (!parameterBlock.getStatements().isEmpty()) { |
|
3901 |
parameterBlock.appendStatement(new BlockStatement(functionBody)); |
|
3902 |
return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements()); |
|
3903 |
} |
|
3904 |
return functionBody; |
|
3905 |
} |
|
3906 |
||
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3907 |
private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { |
24719 | 3908 |
final String defaultFunctionName = getDefaultFunctionName(); |
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3909 |
if (isValidIdentifier(defaultFunctionName)) { |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3910 |
if (isStatement) { |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3911 |
// The name will be used as the LHS of a symbol assignment. We add the anonymous function |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3912 |
// prefix to ensure that it can't clash with another variable. |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3913 |
return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3914 |
} |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3915 |
return defaultFunctionName; |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3916 |
} |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3917 |
return ANON_FUNCTION_PREFIX.symbolName() + functionLine; |
24719 | 3918 |
} |
3919 |
||
24744
5290da85fc3d
8038426: Move all loggers from process wide scope into Global scope
lagergren
parents:
24727
diff
changeset
|
3920 |
private static boolean isValidIdentifier(final String name) { |
37732 | 3921 |
if (name == null || name.isEmpty()) { |
24719 | 3922 |
return false; |
3923 |
} |
|
37732 | 3924 |
if (!Character.isJavaIdentifierStart(name.charAt(0))) { |
24719 | 3925 |
return false; |
3926 |
} |
|
37732 | 3927 |
for (int i = 1; i < name.length(); ++i) { |
3928 |
if (!Character.isJavaIdentifierPart(name.charAt(i))) { |
|
24719 | 3929 |
return false; |
3930 |
} |
|
3931 |
} |
|
3932 |
return true; |
|
3933 |
} |
|
3934 |
||
3935 |
private String getDefaultFunctionName() { |
|
37732 | 3936 |
if (!defaultNames.isEmpty()) { |
24719 | 3937 |
final Object nameExpr = defaultNames.peek(); |
37732 | 3938 |
if (nameExpr instanceof PropertyKey) { |
24719 | 3939 |
markDefaultNameUsed(); |
3940 |
return ((PropertyKey)nameExpr).getPropertyName(); |
|
37732 | 3941 |
} else if (nameExpr instanceof AccessNode) { |
24719 | 3942 |
markDefaultNameUsed(); |
24751 | 3943 |
return ((AccessNode)nameExpr).getProperty(); |
24719 | 3944 |
} |
3945 |
} |
|
3946 |
return null; |
|
3947 |
} |
|
3948 |
||
3949 |
private void markDefaultNameUsed() { |
|
3950 |
defaultNames.pop(); |
|
27974
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3951 |
hideDefaultName(); |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3952 |
} |
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3953 |
|
4eca5d2c0088
8066221: anonymous function statement name clashes with another symbol
attila
parents:
27819
diff
changeset
|
3954 |
private void hideDefaultName() { |
24719 | 3955 |
// Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value |
3956 |
// from. Can't be null |
|
3957 |
defaultNames.push(""); |
|
3958 |
} |
|
3959 |
||
16147 | 3960 |
/** |
3961 |
* FormalParameterList : |
|
3962 |
* Identifier |
|
3963 |
* FormalParameterList , Identifier |
|
3964 |
* |
|
3965 |
* See 13 |
|
3966 |
* |
|
3967 |
* Parse function parameter list. |
|
3968 |
* @return List of parameter nodes. |
|
3969 |
*/ |
|
37732 | 3970 |
private List<IdentNode> formalParameterList(final boolean yield) { |
3971 |
return formalParameterList(RPAREN, yield); |
|
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3972 |
} |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3973 |
|
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3974 |
/** |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3975 |
* Same as the other method of the same name - except that the end |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3976 |
* token type expected is passed as argument to this method. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3977 |
* |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3978 |
* FormalParameterList : |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3979 |
* Identifier |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3980 |
* FormalParameterList , Identifier |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3981 |
* |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3982 |
* See 13 |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3983 |
* |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3984 |
* Parse function parameter list. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3985 |
* @return List of parameter nodes. |
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3986 |
*/ |
37732 | 3987 |
private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) { |
16147 | 3988 |
// Prepare to gather parameters. |
24751 | 3989 |
final ArrayList<IdentNode> parameters = new ArrayList<>(); |
16147 | 3990 |
// Track commas. |
3991 |
boolean first = true; |
|
3992 |
||
17973
d220c8157f25
8015345: Function("}),print('test'),({") should throw SyntaxError
sundar
parents:
17745
diff
changeset
|
3993 |
while (type != endType) { |
16147 | 3994 |
// Comma prior to every argument except the first. |
3995 |
if (!first) { |
|
3996 |
expect(COMMARIGHT); |
|
3997 |
} else { |
|
3998 |
first = false; |
|
3999 |
} |
|
4000 |
||
37732 | 4001 |
boolean restParameter = false; |
4002 |
if (type == ELLIPSIS && isES6()) { |
|
4003 |
next(); |
|
4004 |
restParameter = true; |
|
4005 |
} |
|
4006 |
||
4007 |
if (type == YIELD && yield) { |
|
4008 |
expect(IDENT); |
|
4009 |
} |
|
4010 |
||
4011 |
final long paramToken = token; |
|
4012 |
final int paramLine = line; |
|
4013 |
final String contextString = "function parameter"; |
|
4014 |
IdentNode ident; |
|
4015 |
if (isBindingIdentifier() || restParameter || !isES6()) { |
|
4016 |
ident = bindingIdentifier(contextString); |
|
4017 |
||
4018 |
if (restParameter) { |
|
4019 |
ident = ident.setIsRestParameter(); |
|
4020 |
// rest parameter must be last |
|
4021 |
expectDontAdvance(endType); |
|
4022 |
parameters.add(ident); |
|
4023 |
break; |
|
4024 |
} else if (type == ASSIGN && isES6()) { |
|
4025 |
next(); |
|
4026 |
ident = ident.setIsDefaultParameter(); |
|
4027 |
||
4028 |
if (type == YIELD && yield) { |
|
4029 |
// error: yield in default expression |
|
4030 |
expect(IDENT); |
|
4031 |
} |
|
4032 |
||
4033 |
// default parameter |
|
41422 | 4034 |
final Expression initializer = assignmentExpression(false); |
4035 |
||
4036 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
37732 | 4037 |
if (currentFunction != null) { |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4038 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4039 |
// keep what is seen in source "as is" and save it as parameter expression |
41422 | 4040 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, initializer); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4041 |
currentFunction.addParameterExpression(ident, assignment); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4042 |
} else { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4043 |
// desugar to: param = (param === undefined) ? initializer : param; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4044 |
// possible alternative: if (param === undefined) param = initializer; |
41422 | 4045 |
final BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
4046 |
final TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4047 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4048 |
lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4049 |
} |
37732 | 4050 |
} |
4051 |
} |
|
4052 |
||
41422 | 4053 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4054 |
if (currentFunction != null) { |
4055 |
currentFunction.addParameterBinding(ident); |
|
4056 |
if (ident.isRestParameter() || ident.isDefaultParameter()) { |
|
4057 |
currentFunction.setSimpleParameterList(false); |
|
4058 |
} |
|
4059 |
} |
|
4060 |
} else { |
|
4061 |
final Expression pattern = bindingPattern(); |
|
4062 |
// Introduce synthetic temporary parameter to capture the object to be destructured. |
|
4063 |
ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter(); |
|
4064 |
verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString); |
|
4065 |
||
4066 |
Expression value = ident; |
|
4067 |
if (type == ASSIGN) { |
|
4068 |
next(); |
|
4069 |
ident = ident.setIsDefaultParameter(); |
|
4070 |
||
4071 |
// binding pattern with initializer. desugar to: (param === undefined) ? initializer : param |
|
41422 | 4072 |
final Expression initializer = assignmentExpression(false); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4073 |
|
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4074 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4075 |
// we don't want the synthetic identifier in parse only mode |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4076 |
value = initializer; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4077 |
} else { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4078 |
// TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list) |
41422 | 4079 |
final BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4080 |
value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4081 |
} |
37732 | 4082 |
} |
4083 |
||
41422 | 4084 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4085 |
if (currentFunction != null) { |
4086 |
// destructuring assignment |
|
41422 | 4087 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4088 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4089 |
// in parse-only mode, represent source tree "as is" |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4090 |
if (ident.isDefaultParameter()) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4091 |
currentFunction.addParameterExpression(ident, assignment); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4092 |
} else { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4093 |
currentFunction.addParameterExpression(ident, pattern); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4094 |
} |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4095 |
} else { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4096 |
lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4097 |
} |
37732 | 4098 |
} |
4099 |
} |
|
16147 | 4100 |
parameters.add(ident); |
4101 |
} |
|
4102 |
||
24751 | 4103 |
parameters.trimToSize(); |
16147 | 4104 |
return parameters; |
4105 |
} |
|
4106 |
||
37732 | 4107 |
private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) { |
4108 |
verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() { |
|
41422 | 4109 |
public void accept(final IdentNode identNode) { |
37732 | 4110 |
verifyIdent(identNode, contextString); |
4111 |
||
41422 | 4112 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4113 |
if (currentFunction != null) { |
4114 |
// declare function-scope variables for destructuring bindings |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4115 |
if (!env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4116 |
lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4117 |
} |
37732 | 4118 |
// detect duplicate bounds names in parameter list |
4119 |
currentFunction.addParameterBinding(identNode); |
|
4120 |
currentFunction.setSimpleParameterList(false); |
|
4121 |
} |
|
4122 |
} |
|
4123 |
}); |
|
4124 |
} |
|
4125 |
||
16147 | 4126 |
/** |
4127 |
* FunctionBody : |
|
4128 |
* SourceElements? |
|
4129 |
* |
|
4130 |
* See 13 |
|
4131 |
* |
|
4132 |
* Parse function body. |
|
4133 |
* @return function node (body.) |
|
4134 |
*/ |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4135 |
private Block functionBody(final ParserContextFunctionNode functionNode) { |
17233 | 4136 |
long lastToken = 0L; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4137 |
ParserContextBlockNode body = null; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4138 |
final long bodyToken = token; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4139 |
Block functionBody; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4140 |
int bodyFinish = 0; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4141 |
|
26503 | 4142 |
final boolean parseBody; |
4143 |
Object endParserState = null; |
|
16147 | 4144 |
try { |
4145 |
// Create a new function block. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4146 |
body = newBlock(); |
33888 | 4147 |
if (env._debug_scopes) { |
4148 |
// debug scope options forces everything to be in scope |
|
4149 |
markEval(lc); |
|
4150 |
} |
|
26503 | 4151 |
assert functionNode != null; |
4152 |
final int functionId = functionNode.getId(); |
|
4153 |
parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); |
|
16147 | 4154 |
// Nashorn extension: expression closures |
37732 | 4155 |
if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) { |
16147 | 4156 |
/* |
4157 |
* Example: |
|
4158 |
* |
|
4159 |
* function square(x) x * x; |
|
4160 |
* print(square(3)); |
|
4161 |
*/ |
|
4162 |
||
4163 |
// just expression as function body |
|
37732 | 4164 |
final Expression expr = assignmentExpression(false); |
24719 | 4165 |
lastToken = previousToken; |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4166 |
functionNode.setLastToken(previousToken); |
17233 | 4167 |
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); |
24719 | 4168 |
// EOL uses length field to store the line number |
4169 |
final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); |
|
26503 | 4170 |
// Only create the return node if we aren't skipping nested functions. Note that we aren't |
4171 |
// skipping parsing of these extended functions; they're considered to be small anyway. Also, |
|
4172 |
// they don't end with a single well known token, so it'd be very hard to get correctly (see |
|
4173 |
// the note below for reasoning on skipping happening before instead of after RBRACE for |
|
4174 |
// details). |
|
4175 |
if (parseBody) { |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4176 |
functionNode.setFlag(FunctionNode.HAS_EXPRESSION_BODY); |
26503 | 4177 |
final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); |
4178 |
appendStatement(returnNode); |
|
4179 |
} |
|
37732 | 4180 |
// bodyFinish = finish; |
16147 | 4181 |
} else { |
26505
d29bf8787b43
8057931: Instead of not skipping small functions in parser, make lexer avoid them instead
attila
parents:
26503
diff
changeset
|
4182 |
expectDontAdvance(LBRACE); |
26503 | 4183 |
if (parseBody || !skipFunctionBody(functionNode)) { |
26505
d29bf8787b43
8057931: Instead of not skipping small functions in parser, make lexer avoid them instead
attila
parents:
26503
diff
changeset
|
4184 |
next(); |
26503 | 4185 |
// Gather the function elements. |
4186 |
final List<Statement> prevFunctionDecls = functionDeclarations; |
|
4187 |
functionDeclarations = new ArrayList<>(); |
|
4188 |
try { |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
4189 |
sourceElements(0); |
26503 | 4190 |
addFunctionDeclarations(functionNode); |
4191 |
} finally { |
|
4192 |
functionDeclarations = prevFunctionDecls; |
|
4193 |
} |
|
4194 |
||
4195 |
lastToken = token; |
|
26505
d29bf8787b43
8057931: Instead of not skipping small functions in parser, make lexer avoid them instead
attila
parents:
26503
diff
changeset
|
4196 |
if (parseBody) { |
26503 | 4197 |
// Since the lexer can read ahead and lexify some number of tokens in advance and have |
4198 |
// them buffered in the TokenStream, we need to produce a lexer state as it was just |
|
4199 |
// before it lexified RBRACE, and not whatever is its current (quite possibly well read |
|
4200 |
// ahead) state. |
|
4201 |
endParserState = new ParserState(Token.descPosition(token), line, linePosition); |
|
4202 |
||
4203 |
// NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of |
|
4204 |
// after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the |
|
4205 |
// state after it. The reason is that RBRACE is a well-known token that we can expect and |
|
4206 |
// will never involve us getting into a weird lexer state, and as such is a great reparse |
|
4207 |
// point. Typical example of a weird lexer state after RBRACE would be: |
|
4208 |
// function this_is_skipped() { ... } "use strict"; |
|
4209 |
// because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead |
|
4210 |
// of compensating for the possibility of a string literal (or similar) after RBRACE, |
|
4211 |
// we'll rather just restart parsing from this well-known, friendly token instead. |
|
4212 |
} |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
4213 |
} |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4214 |
bodyFinish = finish; |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4215 |
functionNode.setLastToken(token); |
16147 | 4216 |
expect(RBRACE); |
4217 |
} |
|
4218 |
} finally { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4219 |
restoreBlock(body); |
16147 | 4220 |
} |
26503 | 4221 |
|
4222 |
// NOTE: we can only do alterations to the function node after restoreFunctionNode. |
|
4223 |
||
4224 |
if (parseBody) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4225 |
functionNode.setEndParserState(endParserState); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4226 |
} else if (!body.getStatements().isEmpty()){ |
26503 | 4227 |
// This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see |
4228 |
// skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to |
|
4229 |
// enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as |
|
4230 |
// an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away |
|
4231 |
// nested bodies early if we were supposed to skip 'em. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4232 |
body.setStatements(Collections.<Statement>emptyList()); |
26503 | 4233 |
} |
4234 |
||
4235 |
if (reparsedFunction != null) { |
|
4236 |
// We restore the flags stored in the function's ScriptFunctionData that we got when we first |
|
4237 |
// eagerly parsed the code. We're doing it because some flags would be set based on the |
|
4238 |
// content of the function, or even content of its nested functions, most of which are normally |
|
4239 |
// skipped during an on-demand compilation. |
|
4240 |
final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); |
|
4241 |
if (data != null) { |
|
4242 |
// Data can be null if when we originally parsed the file, we removed the function declaration |
|
4243 |
// as it was dead code. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4244 |
functionNode.setFlag(data.getFunctionFlags()); |
26503 | 4245 |
// This compensates for missing markEval() in case the function contains an inner function |
4246 |
// that contains eval(), that now we didn't discover since we skipped the inner function. |
|
4247 |
if (functionNode.hasNestedEval()) { |
|
4248 |
assert functionNode.hasScopeBlock(); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4249 |
body.setFlag(Block.NEEDS_SCOPE); |
26503 | 4250 |
} |
4251 |
} |
|
4252 |
} |
|
37732 | 4253 |
functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements()); |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4254 |
return functionBody; |
16147 | 4255 |
} |
4256 |
||
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4257 |
private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { |
26503 | 4258 |
if (reparsedFunction == null) { |
4259 |
// Not reparsing, so don't skip any function body. |
|
4260 |
return false; |
|
4261 |
} |
|
4262 |
// Skip to the RBRACE of this function, and continue parsing from there. |
|
4263 |
final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); |
|
4264 |
if (data == null) { |
|
4265 |
// Nested function is not known to the reparsed function. This can happen if the FunctionNode was |
|
4266 |
// in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the |
|
4267 |
// FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. |
|
4268 |
return false; |
|
4269 |
} |
|
4270 |
final ParserState parserState = (ParserState)data.getEndParserState(); |
|
26505
d29bf8787b43
8057931: Instead of not skipping small functions in parser, make lexer avoid them instead
attila
parents:
26503
diff
changeset
|
4271 |
assert parserState != null; |
26503 | 4272 |
|
33414 | 4273 |
if (k < stream.last() && start < parserState.position && parserState.position <= Token.descPosition(stream.get(stream.last()))) { |
4274 |
// RBRACE is already in the token stream, so fast forward to it |
|
4275 |
for (; k < stream.last(); k++) { |
|
34447
ec4c069f9436
8141338: Move jdk.internal.dynalink package to jdk.dynalink
attila
parents:
33888
diff
changeset
|
4276 |
final long nextToken = stream.get(k + 1); |
33414 | 4277 |
if (Token.descPosition(nextToken) == parserState.position && Token.descType(nextToken) == RBRACE) { |
4278 |
token = stream.get(k); |
|
4279 |
type = Token.descType(token); |
|
4280 |
next(); |
|
4281 |
assert type == RBRACE && start == parserState.position; |
|
4282 |
return true; |
|
4283 |
} |
|
4284 |
} |
|
4285 |
} |
|
4286 |
||
26503 | 4287 |
stream.reset(); |
32444 | 4288 |
lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6); |
26503 | 4289 |
line = parserState.line; |
4290 |
linePosition = parserState.linePosition; |
|
4291 |
// Doesn't really matter, but it's safe to treat it as if there were a semicolon before |
|
4292 |
// the RBRACE. |
|
4293 |
type = SEMICOLON; |
|
37732 | 4294 |
scanFirstToken(); |
26503 | 4295 |
|
4296 |
return true; |
|
4297 |
} |
|
4298 |
||
4299 |
/** |
|
4300 |
* Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer |
|
4301 |
* for resuming parsing after skipping a function body. |
|
4302 |
*/ |
|
26646
332e9901f0ed
8058304: Non-serializable fields in serializable classes
hannesw
parents:
26505
diff
changeset
|
4303 |
private static class ParserState implements Serializable { |
26503 | 4304 |
private final int position; |
4305 |
private final int line; |
|
4306 |
private final int linePosition; |
|
4307 |
||
26646
332e9901f0ed
8058304: Non-serializable fields in serializable classes
hannesw
parents:
26505
diff
changeset
|
4308 |
private static final long serialVersionUID = -2382565130754093694L; |
332e9901f0ed
8058304: Non-serializable fields in serializable classes
hannesw
parents:
26505
diff
changeset
|
4309 |
|
26503 | 4310 |
ParserState(final int position, final int line, final int linePosition) { |
4311 |
this.position = position; |
|
4312 |
this.line = line; |
|
4313 |
this.linePosition = linePosition; |
|
4314 |
} |
|
4315 |
||
32444 | 4316 |
Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) { |
4317 |
final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true); |
|
26503 | 4318 |
newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); |
4319 |
return newLexer; |
|
4320 |
} |
|
4321 |
} |
|
4322 |
||
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4323 |
private void printAST(final FunctionNode functionNode) { |
37732 | 4324 |
if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) { |
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4325 |
env.getErr().println(new ASTWriter(functionNode)); |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4326 |
} |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4327 |
|
37732 | 4328 |
if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) { |
26065
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4329 |
env.getErr().println(new PrintVisitor(functionNode, true, false)); |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4330 |
} |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4331 |
} |
d15adb218527
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
sundar
parents:
26055
diff
changeset
|
4332 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4333 |
private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { |
17233 | 4334 |
VarNode lastDecl = null; |
4335 |
for (int i = functionDeclarations.size() - 1; i >= 0; i--) { |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4336 |
Statement decl = functionDeclarations.get(i); |
17233 | 4337 |
if (lastDecl == null && decl instanceof VarNode) { |
4338 |
decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
4339 |
functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); |
17233 | 4340 |
} |
4341 |
prependStatement(decl); |
|
4342 |
} |
|
4343 |
} |
|
4344 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4345 |
private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4346 |
if (env._parse_only || earlyError) { |
18632
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4347 |
throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); |
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4348 |
} |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4349 |
final ArrayList<Expression> args = new ArrayList<>(); |
16147 | 4350 |
args.add(lhs); |
4351 |
if (rhs == null) { |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
4352 |
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); |
16147 | 4353 |
} else { |
4354 |
args.add(rhs); |
|
4355 |
} |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
4356 |
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); |
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
4357 |
return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); |
16147 | 4358 |
} |
4359 |
||
4360 |
/** |
|
4361 |
* PostfixExpression : |
|
4362 |
* LeftHandSideExpression |
|
4363 |
* LeftHandSideExpression ++ // [no LineTerminator here] |
|
4364 |
* LeftHandSideExpression -- // [no LineTerminator here] |
|
4365 |
* |
|
4366 |
* See 11.3 |
|
4367 |
* |
|
4368 |
* UnaryExpression : |
|
4369 |
* PostfixExpression |
|
4370 |
* delete UnaryExpression |
|
32437
153cb8aeb422
8134865: Need to restore for container block from lexical context in finally
aw
parents:
32245
diff
changeset
|
4371 |
* void UnaryExpression |
16147 | 4372 |
* typeof UnaryExpression |
4373 |
* ++ UnaryExpression |
|
4374 |
* -- UnaryExpression |
|
4375 |
* + UnaryExpression |
|
4376 |
* - UnaryExpression |
|
4377 |
* ~ UnaryExpression |
|
4378 |
* ! UnaryExpression |
|
4379 |
* |
|
4380 |
* See 11.4 |
|
4381 |
* |
|
4382 |
* Parse unary expression. |
|
4383 |
* @return Expression node. |
|
4384 |
*/ |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4385 |
private Expression unaryExpression() { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4386 |
final int unaryLine = line; |
16147 | 4387 |
final long unaryToken = token; |
4388 |
||
4389 |
switch (type) { |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4390 |
case DELETE: { |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4391 |
next(); |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4392 |
final Expression expr = unaryExpression(); |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4393 |
if (expr instanceof BaseNode || expr instanceof IdentNode) { |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4394 |
return new UnaryNode(unaryToken, expr); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4395 |
} |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4396 |
appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4397 |
return LiteralNode.newInstance(unaryToken, finish, true); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
4398 |
} |
46169
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4399 |
case ADD: |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4400 |
case SUB: { |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4401 |
final TokenType opType = type; |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4402 |
next(); |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4403 |
final Expression expr = unaryExpression(); |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4404 |
return new UnaryNode(Token.recast(unaryToken, (opType == TokenType.ADD) ? TokenType.POS : TokenType.NEG), expr); |
b385216af0ed
8185252: Unary minus and plus use wrong node Kind
hannesw
parents:
41983
diff
changeset
|
4405 |
} |
16147 | 4406 |
case VOID: |
4407 |
case TYPEOF: |
|
4408 |
case BIT_NOT: |
|
4409 |
case NOT: |
|
4410 |
next(); |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4411 |
final Expression expr = unaryExpression(); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
4412 |
return new UnaryNode(unaryToken, expr); |
16147 | 4413 |
|
4414 |
case INCPREFIX: |
|
4415 |
case DECPREFIX: |
|
4416 |
final TokenType opType = type; |
|
4417 |
next(); |
|
4418 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4419 |
final Expression lhs = leftHandSideExpression(); |
16147 | 4420 |
// ++, -- without operand.. |
4421 |
if (lhs == null) { |
|
18632
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4422 |
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); |
16147 | 4423 |
} |
18632
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4424 |
|
37732 | 4425 |
return verifyIncDecExpression(unaryToken, opType, lhs, false); |
16147 | 4426 |
|
4427 |
default: |
|
4428 |
break; |
|
4429 |
} |
|
4430 |
||
41422 | 4431 |
final Expression expression = leftHandSideExpression(); |
16147 | 4432 |
|
4433 |
if (last != EOL) { |
|
4434 |
switch (type) { |
|
4435 |
case INCPREFIX: |
|
4436 |
case DECPREFIX: |
|
37732 | 4437 |
final long opToken = token; |
16147 | 4438 |
final TokenType opType = type; |
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4439 |
final Expression lhs = expression; |
18632
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4440 |
// ++, -- without operand.. |
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4441 |
if (lhs == null) { |
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4442 |
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); |
93017277615e
8019553: NPE on illegal l-value for increment and decrement
sundar
parents:
18629
diff
changeset
|
4443 |
} |
16147 | 4444 |
next(); |
37732 | 4445 |
|
4446 |
return verifyIncDecExpression(opToken, opType, lhs, true); |
|
16147 | 4447 |
default: |
4448 |
break; |
|
4449 |
} |
|
4450 |
} |
|
4451 |
||
4452 |
if (expression == null) { |
|
17233 | 4453 |
throw error(AbstractParser.message("expected.operand", type.getNameOrType())); |
16147 | 4454 |
} |
4455 |
||
4456 |
return expression; |
|
4457 |
} |
|
4458 |
||
37732 | 4459 |
private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) { |
4460 |
assert lhs != null; |
|
4461 |
||
4462 |
if (!(lhs instanceof AccessNode || |
|
4463 |
lhs instanceof IndexNode || |
|
4464 |
lhs instanceof IdentNode)) { |
|
4465 |
return referenceError(lhs, null, env._early_lvalue_error); |
|
4466 |
} |
|
4467 |
||
4468 |
if (lhs instanceof IdentNode) { |
|
4469 |
if (!checkIdentLValue((IdentNode)lhs)) { |
|
4470 |
return referenceError(lhs, null, false); |
|
4471 |
} |
|
4472 |
verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); |
|
4473 |
} |
|
4474 |
||
4475 |
return incDecExpression(unaryToken, opType, lhs, isPostfix); |
|
4476 |
} |
|
4477 |
||
16147 | 4478 |
/** |
32245
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4479 |
* {@code |
16147 | 4480 |
* MultiplicativeExpression : |
4481 |
* UnaryExpression |
|
4482 |
* MultiplicativeExpression * UnaryExpression |
|
4483 |
* MultiplicativeExpression / UnaryExpression |
|
4484 |
* MultiplicativeExpression % UnaryExpression |
|
4485 |
* |
|
4486 |
* See 11.5 |
|
4487 |
* |
|
4488 |
* AdditiveExpression : |
|
4489 |
* MultiplicativeExpression |
|
4490 |
* AdditiveExpression + MultiplicativeExpression |
|
4491 |
* AdditiveExpression - MultiplicativeExpression |
|
4492 |
* |
|
4493 |
* See 11.6 |
|
4494 |
* |
|
4495 |
* ShiftExpression : |
|
4496 |
* AdditiveExpression |
|
4497 |
* ShiftExpression << AdditiveExpression |
|
4498 |
* ShiftExpression >> AdditiveExpression |
|
4499 |
* ShiftExpression >>> AdditiveExpression |
|
4500 |
* |
|
4501 |
* See 11.7 |
|
4502 |
* |
|
4503 |
* RelationalExpression : |
|
4504 |
* ShiftExpression |
|
4505 |
* RelationalExpression < ShiftExpression |
|
4506 |
* RelationalExpression > ShiftExpression |
|
4507 |
* RelationalExpression <= ShiftExpression |
|
4508 |
* RelationalExpression >= ShiftExpression |
|
4509 |
* RelationalExpression instanceof ShiftExpression |
|
4510 |
* RelationalExpression in ShiftExpression // if !noIf |
|
4511 |
* |
|
4512 |
* See 11.8 |
|
4513 |
* |
|
4514 |
* RelationalExpression |
|
4515 |
* EqualityExpression == RelationalExpression |
|
4516 |
* EqualityExpression != RelationalExpression |
|
4517 |
* EqualityExpression === RelationalExpression |
|
4518 |
* EqualityExpression !== RelationalExpression |
|
4519 |
* |
|
4520 |
* See 11.9 |
|
4521 |
* |
|
4522 |
* BitwiseANDExpression : |
|
4523 |
* EqualityExpression |
|
4524 |
* BitwiseANDExpression & EqualityExpression |
|
4525 |
* |
|
4526 |
* BitwiseXORExpression : |
|
4527 |
* BitwiseANDExpression |
|
4528 |
* BitwiseXORExpression ^ BitwiseANDExpression |
|
4529 |
* |
|
4530 |
* BitwiseORExpression : |
|
4531 |
* BitwiseXORExpression |
|
4532 |
* BitwiseORExpression | BitwiseXORExpression |
|
4533 |
* |
|
4534 |
* See 11.10 |
|
4535 |
* |
|
4536 |
* LogicalANDExpression : |
|
4537 |
* BitwiseORExpression |
|
4538 |
* LogicalANDExpression && BitwiseORExpression |
|
4539 |
* |
|
4540 |
* LogicalORExpression : |
|
4541 |
* LogicalANDExpression |
|
4542 |
* LogicalORExpression || LogicalANDExpression |
|
4543 |
* |
|
4544 |
* See 11.11 |
|
4545 |
* |
|
4546 |
* ConditionalExpression : |
|
4547 |
* LogicalORExpression |
|
4548 |
* LogicalORExpression ? AssignmentExpression : AssignmentExpression |
|
4549 |
* |
|
4550 |
* See 11.12 |
|
4551 |
* |
|
4552 |
* AssignmentExpression : |
|
4553 |
* ConditionalExpression |
|
4554 |
* LeftHandSideExpression AssignmentOperator AssignmentExpression |
|
4555 |
* |
|
4556 |
* AssignmentOperator : |
|
4557 |
* = *= /= %= += -= <<= >>= >>>= &= ^= |= |
|
4558 |
* |
|
4559 |
* See 11.13 |
|
4560 |
* |
|
4561 |
* Expression : |
|
4562 |
* AssignmentExpression |
|
4563 |
* Expression , AssignmentExpression |
|
4564 |
* |
|
4565 |
* See 11.14 |
|
32245
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4566 |
* } |
16147 | 4567 |
* |
4568 |
* Parse expression. |
|
4569 |
* @return Expression node. |
|
4570 |
*/ |
|
32245
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4571 |
protected Expression expression() { |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4572 |
// This method is protected so that subclass can get details |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4573 |
// at expression start point! |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4574 |
|
16147 | 4575 |
// Include commas in expression parsing. |
37732 | 4576 |
return expression(false); |
4577 |
} |
|
4578 |
||
4579 |
private Expression expression(final boolean noIn) { |
|
4580 |
Expression assignmentExpression = assignmentExpression(noIn); |
|
4581 |
while (type == COMMARIGHT) { |
|
41422 | 4582 |
final long commaToken = token; |
37732 | 4583 |
next(); |
4584 |
||
4585 |
boolean rhsRestParameter = false; |
|
4586 |
if (type == ELLIPSIS && isES6()) { |
|
4587 |
// (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error). |
|
4588 |
// But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead. |
|
4589 |
if (isRestParameterEndOfArrowFunctionParameterList()) { |
|
4590 |
next(); |
|
4591 |
rhsRestParameter = true; |
|
4592 |
} |
|
4593 |
} |
|
4594 |
||
4595 |
Expression rhs = assignmentExpression(noIn); |
|
4596 |
||
4597 |
if (rhsRestParameter) { |
|
4598 |
rhs = ((IdentNode)rhs).setIsRestParameter(); |
|
4599 |
// Our only valid move is to end Expression here and continue with ArrowFunction. |
|
4600 |
// We've already checked that this is the parameter list of an arrow function (see above). |
|
4601 |
// RPAREN is next, so we'll finish the binary expression and drop out of the loop. |
|
4602 |
assert type == RPAREN; |
|
4603 |
} |
|
4604 |
||
4605 |
assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs); |
|
4606 |
} |
|
4607 |
return assignmentExpression; |
|
4608 |
} |
|
4609 |
||
4610 |
private Expression expression(final int minPrecedence, final boolean noIn) { |
|
4611 |
return expression(unaryExpression(), minPrecedence, noIn); |
|
16147 | 4612 |
} |
17233 | 4613 |
|
24751 | 4614 |
private JoinPredecessorExpression joinPredecessorExpression() { |
4615 |
return new JoinPredecessorExpression(expression()); |
|
4616 |
} |
|
4617 |
||
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4618 |
private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { |
16147 | 4619 |
// Get the precedence of the next operator. |
4620 |
int precedence = type.getPrecedence(); |
|
18867
bc91e3fcc5ba
8013925: Remove symbol fields from nodes that don't need them
attila
parents:
18853
diff
changeset
|
4621 |
Expression lhs = exprLhs; |
16147 | 4622 |
|
4623 |
// While greater precedence. |
|
4624 |
while (type.isOperator(noIn) && precedence >= minPrecedence) { |
|
4625 |
// Capture the operator token. |
|
4626 |
final long op = token; |
|
4627 |
||
4628 |
if (type == TERNARY) { |
|
4629 |
// Skip operator. |
|
4630 |
next(); |
|
4631 |
||
4632 |
// Pass expression. Middle expression of a conditional expression can be a "in" |
|
4633 |
// expression - even in the contexts where "in" is not permitted. |
|
24751 | 4634 |
final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); |
16147 | 4635 |
|
4636 |
expect(COLON); |
|
4637 |
||
4638 |
// Fail expression. |
|
24751 | 4639 |
final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); |
16147 | 4640 |
|
4641 |
// Build up node. |
|
24751 | 4642 |
lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); |
16147 | 4643 |
} else { |
4644 |
// Skip operator. |
|
4645 |
next(); |
|
4646 |
||
4647 |
// Get the next primary expression. |
|
24719 | 4648 |
Expression rhs; |
4649 |
final boolean isAssign = Token.descType(op) == ASSIGN; |
|
4650 |
if(isAssign) { |
|
4651 |
defaultNames.push(lhs); |
|
16147 | 4652 |
} |
24719 | 4653 |
try { |
4654 |
rhs = unaryExpression(); |
|
4655 |
// Get precedence of next operator. |
|
4656 |
int nextPrecedence = type.getPrecedence(); |
|
4657 |
||
4658 |
// Subtask greater precedence. |
|
4659 |
while (type.isOperator(noIn) && |
|
4660 |
(nextPrecedence > precedence || |
|
4661 |
nextPrecedence == precedence && !type.isLeftAssociative())) { |
|
4662 |
rhs = expression(rhs, nextPrecedence, noIn); |
|
4663 |
nextPrecedence = type.getPrecedence(); |
|
4664 |
} |
|
4665 |
} finally { |
|
4666 |
if(isAssign) { |
|
4667 |
defaultNames.pop(); |
|
4668 |
} |
|
4669 |
} |
|
16147 | 4670 |
lhs = verifyAssignment(op, lhs, rhs); |
4671 |
} |
|
4672 |
||
4673 |
precedence = type.getPrecedence(); |
|
4674 |
} |
|
4675 |
||
4676 |
return lhs; |
|
4677 |
} |
|
4678 |
||
37732 | 4679 |
/** |
4680 |
* AssignmentExpression. |
|
4681 |
* |
|
4682 |
* AssignmentExpression[In, Yield] : |
|
4683 |
* ConditionalExpression[?In, ?Yield] |
|
4684 |
* [+Yield] YieldExpression[?In] |
|
4685 |
* ArrowFunction[?In, ?Yield] |
|
4686 |
* LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield] |
|
4687 |
* LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield] |
|
38807 | 4688 |
* |
4689 |
* @param noIn {@code true} if IN operator should be ignored. |
|
4690 |
* @return the assignment expression |
|
37732 | 4691 |
*/ |
32245
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4692 |
protected Expression assignmentExpression(final boolean noIn) { |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4693 |
// This method is protected so that subclass can get details |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4694 |
// at assignment expression start point! |
80164edf8a10
8133872: Expression completion should work on contexts where an expression is accepted
sundar
parents:
31485
diff
changeset
|
4695 |
|
37732 | 4696 |
if (type == YIELD && inGeneratorFunction() && isES6()) { |
4697 |
return yieldExpression(noIn); |
|
4698 |
} |
|
4699 |
||
4700 |
final long startToken = token; |
|
4701 |
final int startLine = line; |
|
4702 |
final Expression exprLhs = conditionalExpression(noIn); |
|
4703 |
||
4704 |
if (type == ARROW && isES6()) { |
|
4705 |
if (checkNoLineTerminator()) { |
|
4706 |
final Expression paramListExpr; |
|
4707 |
if (exprLhs instanceof ExpressionList) { |
|
4708 |
paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0)); |
|
4709 |
} else { |
|
4710 |
paramListExpr = exprLhs; |
|
4711 |
} |
|
4712 |
return arrowFunction(startToken, startLine, paramListExpr); |
|
4713 |
} |
|
4714 |
} |
|
4715 |
assert !(exprLhs instanceof ExpressionList); |
|
4716 |
||
4717 |
if (isAssignmentOperator(type)) { |
|
4718 |
final boolean isAssign = type == ASSIGN; |
|
4719 |
if (isAssign) { |
|
4720 |
defaultNames.push(exprLhs); |
|
4721 |
} |
|
4722 |
try { |
|
4723 |
final long assignToken = token; |
|
4724 |
next(); |
|
4725 |
final Expression exprRhs = assignmentExpression(noIn); |
|
4726 |
return verifyAssignment(assignToken, exprLhs, exprRhs); |
|
4727 |
} finally { |
|
4728 |
if (isAssign) { |
|
4729 |
defaultNames.pop(); |
|
4730 |
} |
|
4731 |
} |
|
4732 |
} else { |
|
4733 |
return exprLhs; |
|
4734 |
} |
|
4735 |
} |
|
4736 |
||
4737 |
/** |
|
4738 |
* Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}? |
|
4739 |
*/ |
|
41422 | 4740 |
private static boolean isAssignmentOperator(final TokenType type) { |
37732 | 4741 |
switch (type) { |
4742 |
case ASSIGN: |
|
4743 |
case ASSIGN_ADD: |
|
4744 |
case ASSIGN_BIT_AND: |
|
4745 |
case ASSIGN_BIT_OR: |
|
4746 |
case ASSIGN_BIT_XOR: |
|
4747 |
case ASSIGN_DIV: |
|
4748 |
case ASSIGN_MOD: |
|
4749 |
case ASSIGN_MUL: |
|
4750 |
case ASSIGN_SAR: |
|
4751 |
case ASSIGN_SHL: |
|
4752 |
case ASSIGN_SHR: |
|
4753 |
case ASSIGN_SUB: |
|
4754 |
return true; |
|
4755 |
} |
|
4756 |
return false; |
|
4757 |
} |
|
4758 |
||
4759 |
/** |
|
4760 |
* ConditionalExpression. |
|
4761 |
*/ |
|
41422 | 4762 |
private Expression conditionalExpression(final boolean noIn) { |
37732 | 4763 |
return expression(TERNARY.getPrecedence(), noIn); |
4764 |
} |
|
4765 |
||
4766 |
/** |
|
4767 |
* ArrowFunction. |
|
4768 |
* |
|
4769 |
* @param startToken start token of the ArrowParameters expression |
|
4770 |
* @param functionLine start line of the arrow function |
|
4771 |
* @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list) |
|
4772 |
*/ |
|
4773 |
private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) { |
|
4774 |
// caller needs to check that there's no LineTerminator between parameter list and arrow |
|
4775 |
assert type != ARROW || checkNoLineTerminator(); |
|
4776 |
expect(ARROW); |
|
4777 |
||
4778 |
final long functionToken = Token.recast(startToken, ARROW); |
|
37835
78bffb8c47c3
8156492: ClassFormatError thrown when arrow function is used
sundar
parents:
37732
diff
changeset
|
4779 |
final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), NameCodec.encode("=>:") + functionLine); |
37732 | 4780 |
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null); |
4781 |
functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
4782 |
||
4783 |
lc.push(functionNode); |
|
4784 |
try { |
|
41422 | 4785 |
final ParserContextBlockNode parameterBlock = newBlock(); |
37732 | 4786 |
final List<IdentNode> parameters; |
4787 |
try { |
|
4788 |
parameters = convertArrowFunctionParameterList(paramListExpr, functionLine); |
|
4789 |
functionNode.setParameters(parameters); |
|
4790 |
||
4791 |
if (!functionNode.isSimpleParameterList()) { |
|
4792 |
markEvalInArrowParameterList(parameterBlock); |
|
4793 |
} |
|
4794 |
} finally { |
|
4795 |
restoreBlock(parameterBlock); |
|
4796 |
} |
|
4797 |
Block functionBody = functionBody(functionNode); |
|
4798 |
||
4799 |
functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
|
4800 |
||
4801 |
verifyParameterList(parameters, functionNode); |
|
4802 |
||
4803 |
final FunctionNode function = createFunctionNode( |
|
4804 |
functionNode, |
|
4805 |
functionToken, |
|
4806 |
name, |
|
4807 |
parameters, |
|
4808 |
FunctionNode.Kind.ARROW, |
|
4809 |
functionLine, |
|
4810 |
functionBody); |
|
4811 |
return function; |
|
4812 |
} finally { |
|
4813 |
lc.pop(functionNode); |
|
4814 |
} |
|
4815 |
} |
|
4816 |
||
4817 |
private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) { |
|
4818 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
4819 |
final ParserContextFunctionNode current = iter.next(); |
|
4820 |
final ParserContextFunctionNode parent = iter.next(); |
|
4821 |
||
4822 |
if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) { |
|
4823 |
// we might have flagged has-eval in the parent function during parsing the parameter list, |
|
4824 |
// if the parameter list contains eval; must tag arrow function as has-eval. |
|
4825 |
for (final Statement st : parameterBlock.getStatements()) { |
|
4826 |
st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
|
4827 |
@Override |
|
4828 |
public boolean enterCallNode(final CallNode callNode) { |
|
4829 |
if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) { |
|
4830 |
current.setFlag(FunctionNode.HAS_EVAL); |
|
4831 |
} |
|
4832 |
return true; |
|
4833 |
} |
|
4834 |
}); |
|
4835 |
} |
|
4836 |
// TODO: function containing the arrow function should not be flagged has-eval |
|
4837 |
} |
|
4838 |
} |
|
4839 |
||
4840 |
private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) { |
|
4841 |
final List<IdentNode> parameters; |
|
4842 |
if (paramListExpr == null) { |
|
4843 |
// empty parameter list, i.e. () => |
|
4844 |
parameters = Collections.emptyList(); |
|
4845 |
} else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) { |
|
4846 |
parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine)); |
|
4847 |
} else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) { |
|
4848 |
parameters = new ArrayList<>(); |
|
4849 |
Expression car = paramListExpr; |
|
4850 |
do { |
|
4851 |
final Expression cdr = ((BinaryNode) car).rhs(); |
|
4852 |
parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine)); |
|
4853 |
car = ((BinaryNode) car).lhs(); |
|
4854 |
} while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT); |
|
4855 |
parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine)); |
|
4856 |
} else { |
|
4857 |
throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken()); |
|
4858 |
} |
|
4859 |
return parameters; |
|
4860 |
} |
|
4861 |
||
41422 | 4862 |
private IdentNode verifyArrowParameter(final Expression param, final int index, final int paramLine) { |
37732 | 4863 |
final String contextString = "function parameter"; |
4864 |
if (param instanceof IdentNode) { |
|
41422 | 4865 |
final IdentNode ident = (IdentNode)param; |
37732 | 4866 |
verifyStrictIdent(ident, contextString); |
41422 | 4867 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4868 |
if (currentFunction != null) { |
4869 |
currentFunction.addParameterBinding(ident); |
|
4870 |
} |
|
4871 |
return ident; |
|
4872 |
} |
|
4873 |
||
4874 |
if (param.isTokenType(ASSIGN)) { |
|
41422 | 4875 |
final Expression lhs = ((BinaryNode) param).lhs(); |
4876 |
final long paramToken = lhs.getToken(); |
|
4877 |
final Expression initializer = ((BinaryNode) param).rhs(); |
|
37732 | 4878 |
if (lhs instanceof IdentNode) { |
4879 |
// default parameter |
|
41422 | 4880 |
final IdentNode ident = (IdentNode) lhs; |
4881 |
||
4882 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
37732 | 4883 |
if (currentFunction != null) { |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4884 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4885 |
currentFunction.addParameterExpression(ident, param); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4886 |
} else { |
41422 | 4887 |
final BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
4888 |
final TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4889 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4890 |
lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4891 |
} |
37732 | 4892 |
|
4893 |
currentFunction.addParameterBinding(ident); |
|
4894 |
currentFunction.setSimpleParameterList(false); |
|
4895 |
} |
|
4896 |
return ident; |
|
4897 |
} else if (isDestructuringLhs(lhs)) { |
|
4898 |
// binding pattern with initializer |
|
4899 |
// Introduce synthetic temporary parameter to capture the object to be destructured. |
|
41422 | 4900 |
final IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter(); |
37732 | 4901 |
verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); |
4902 |
||
41422 | 4903 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4904 |
if (currentFunction != null) { |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4905 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4906 |
currentFunction.addParameterExpression(ident, param); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4907 |
} else { |
41422 | 4908 |
final BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
4909 |
final TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4910 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value); |
|
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4911 |
lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4912 |
} |
37732 | 4913 |
} |
4914 |
return ident; |
|
4915 |
} |
|
4916 |
} else if (isDestructuringLhs(param)) { |
|
4917 |
// binding pattern |
|
41422 | 4918 |
final long paramToken = param.getToken(); |
37732 | 4919 |
|
4920 |
// Introduce synthetic temporary parameter to capture the object to be destructured. |
|
41422 | 4921 |
final IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter(); |
37732 | 4922 |
verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); |
4923 |
||
41422 | 4924 |
final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
37732 | 4925 |
if (currentFunction != null) { |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4926 |
if (env._parse_only) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4927 |
currentFunction.addParameterExpression(ident, param); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4928 |
} else { |
41422 | 4929 |
final BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4930 |
lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
4931 |
} |
37732 | 4932 |
} |
4933 |
return ident; |
|
4934 |
} |
|
4935 |
throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken()); |
|
4936 |
} |
|
4937 |
||
4938 |
private boolean checkNoLineTerminator() { |
|
4939 |
assert type == ARROW; |
|
4940 |
if (last == RPAREN) { |
|
4941 |
return true; |
|
4942 |
} else if (last == IDENT) { |
|
4943 |
return true; |
|
4944 |
} |
|
4945 |
for (int i = k - 1; i >= 0; i--) { |
|
41422 | 4946 |
final TokenType t = T(i); |
37732 | 4947 |
switch (t) { |
4948 |
case RPAREN: |
|
4949 |
case IDENT: |
|
4950 |
return true; |
|
4951 |
case EOL: |
|
4952 |
return false; |
|
4953 |
case COMMENT: |
|
4954 |
continue; |
|
4955 |
default: |
|
4956 |
if (t.getKind() == TokenKind.FUTURESTRICT) { |
|
4957 |
return true; |
|
4958 |
} |
|
4959 |
return false; |
|
4960 |
} |
|
4961 |
} |
|
4962 |
return false; |
|
4963 |
} |
|
4964 |
||
4965 |
/** |
|
4966 |
* Peek ahead to see if what follows after the ellipsis is a rest parameter |
|
4967 |
* at the end of an arrow function parameter list. |
|
4968 |
*/ |
|
4969 |
private boolean isRestParameterEndOfArrowFunctionParameterList() { |
|
4970 |
assert type == ELLIPSIS; |
|
4971 |
// find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT |
|
4972 |
int i = 1; |
|
4973 |
for (;;) { |
|
41422 | 4974 |
final TokenType t = T(k + i++); |
37732 | 4975 |
if (t == IDENT) { |
4976 |
break; |
|
4977 |
} else if (t == EOL || t == COMMENT) { |
|
4978 |
continue; |
|
4979 |
} else { |
|
4980 |
return false; |
|
4981 |
} |
|
4982 |
} |
|
4983 |
for (;;) { |
|
41422 | 4984 |
final TokenType t = T(k + i++); |
37732 | 4985 |
if (t == RPAREN) { |
4986 |
break; |
|
4987 |
} else if (t == EOL || t == COMMENT) { |
|
4988 |
continue; |
|
4989 |
} else { |
|
4990 |
return false; |
|
4991 |
} |
|
4992 |
} |
|
4993 |
for (;;) { |
|
41422 | 4994 |
final TokenType t = T(k + i++); |
37732 | 4995 |
if (t == ARROW) { |
4996 |
break; |
|
4997 |
} else if (t == COMMENT) { |
|
4998 |
continue; |
|
4999 |
} else { |
|
5000 |
return false; |
|
5001 |
} |
|
5002 |
} |
|
5003 |
return true; |
|
16147 | 5004 |
} |
5005 |
||
5006 |
/** |
|
5007 |
* Parse an end of line. |
|
5008 |
*/ |
|
5009 |
private void endOfLine() { |
|
5010 |
switch (type) { |
|
5011 |
case SEMICOLON: |
|
5012 |
case EOL: |
|
5013 |
next(); |
|
5014 |
break; |
|
5015 |
case RPAREN: |
|
5016 |
case RBRACKET: |
|
5017 |
case RBRACE: |
|
5018 |
case EOF: |
|
5019 |
break; |
|
5020 |
default: |
|
5021 |
if (last != EOL) { |
|
5022 |
expect(SEMICOLON); |
|
5023 |
} |
|
5024 |
break; |
|
5025 |
} |
|
5026 |
} |
|
5027 |
||
33414 | 5028 |
/** |
5029 |
* Parse untagged template literal as string concatenation. |
|
5030 |
*/ |
|
5031 |
private Expression templateLiteral() { |
|
5032 |
assert type == TEMPLATE || type == TEMPLATE_HEAD; |
|
5033 |
final boolean noSubstitutionTemplate = type == TEMPLATE; |
|
5034 |
long lastLiteralToken = token; |
|
5035 |
LiteralNode<?> literal = getLiteral(); |
|
5036 |
if (noSubstitutionTemplate) { |
|
5037 |
return literal; |
|
5038 |
} |
|
5039 |
||
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5040 |
if (env._parse_only) { |
41422 | 5041 |
final List<Expression> exprs = new ArrayList<>(); |
39662
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5042 |
exprs.add(literal); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5043 |
TokenType lastLiteralType; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5044 |
do { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5045 |
final Expression expression = expression(); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5046 |
if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5047 |
throw error(AbstractParser.message("unterminated.template.expression"), token); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5048 |
} |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5049 |
exprs.add(expression); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5050 |
lastLiteralType = type; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5051 |
literal = getLiteral(); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5052 |
exprs.add(literal); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5053 |
} while (lastLiteralType == TEMPLATE_MIDDLE); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5054 |
return new TemplateLiteral(exprs); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5055 |
} else { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5056 |
Expression concat = literal; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5057 |
TokenType lastLiteralType; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5058 |
do { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5059 |
final Expression expression = expression(); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5060 |
if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5061 |
throw error(AbstractParser.message("unterminated.template.expression"), token); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5062 |
} |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5063 |
concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, expression); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5064 |
lastLiteralType = type; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5065 |
lastLiteralToken = token; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5066 |
literal = getLiteral(); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5067 |
concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, literal); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5068 |
} while (lastLiteralType == TEMPLATE_MIDDLE); |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5069 |
return concat; |
e2b36a3779b9
8149929: Nashorn Parser API needs to be updated for ES6
sundar
parents:
39077
diff
changeset
|
5070 |
} |
33414 | 5071 |
} |
5072 |
||
5073 |
/** |
|
5074 |
* Parse tagged template literal as argument list. |
|
5075 |
* @return argument list for a tag function call (template object, ...substitutions) |
|
5076 |
*/ |
|
5077 |
private List<Expression> templateLiteralArgumentList() { |
|
5078 |
assert type == TEMPLATE || type == TEMPLATE_HEAD; |
|
5079 |
final ArrayList<Expression> argumentList = new ArrayList<>(); |
|
5080 |
final ArrayList<Expression> rawStrings = new ArrayList<>(); |
|
5081 |
final ArrayList<Expression> cookedStrings = new ArrayList<>(); |
|
5082 |
argumentList.add(null); // filled at the end |
|
5083 |
||
5084 |
final long templateToken = token; |
|
5085 |
final boolean hasSubstitutions = type == TEMPLATE_HEAD; |
|
5086 |
addTemplateLiteralString(rawStrings, cookedStrings); |
|
5087 |
||
5088 |
if (hasSubstitutions) { |
|
5089 |
TokenType lastLiteralType; |
|
5090 |
do { |
|
34447
ec4c069f9436
8141338: Move jdk.internal.dynalink package to jdk.dynalink
attila
parents:
33888
diff
changeset
|
5091 |
final Expression expression = expression(); |
33414 | 5092 |
if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { |
5093 |
throw error(AbstractParser.message("unterminated.template.expression"), token); |
|
5094 |
} |
|
5095 |
argumentList.add(expression); |
|
5096 |
||
5097 |
lastLiteralType = type; |
|
5098 |
addTemplateLiteralString(rawStrings, cookedStrings); |
|
5099 |
} while (lastLiteralType == TEMPLATE_MIDDLE); |
|
5100 |
} |
|
5101 |
||
5102 |
final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings); |
|
5103 |
final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings); |
|
5104 |
final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray); |
|
5105 |
argumentList.set(0, templateObject); |
|
5106 |
return optimizeList(argumentList); |
|
5107 |
} |
|
5108 |
||
5109 |
private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, final ArrayList<Expression> cookedStrings) { |
|
5110 |
final long stringToken = token; |
|
5111 |
final String rawString = lexer.valueOfRawString(stringToken); |
|
5112 |
final String cookedString = (String) getValue(); |
|
5113 |
next(); |
|
5114 |
rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString)); |
|
5115 |
cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); |
|
5116 |
} |
|
5117 |
||
37732 | 5118 |
|
5119 |
/** |
|
5120 |
* Parse a module. |
|
5121 |
* |
|
5122 |
* Module : |
|
5123 |
* ModuleBody? |
|
5124 |
* |
|
5125 |
* ModuleBody : |
|
5126 |
* ModuleItemList |
|
5127 |
*/ |
|
5128 |
private FunctionNode module(final String moduleName) { |
|
41422 | 5129 |
final boolean oldStrictMode = isStrictMode; |
37732 | 5130 |
try { |
5131 |
isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1) |
|
5132 |
||
5133 |
// Make a pseudo-token for the script holding its start and length. |
|
41422 | 5134 |
final int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish); |
37732 | 5135 |
final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart); |
5136 |
final int functionLine = line; |
|
5137 |
||
5138 |
final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName); |
|
5139 |
final ParserContextFunctionNode script = createParserContextFunctionNode( |
|
5140 |
ident, |
|
5141 |
functionToken, |
|
5142 |
FunctionNode.Kind.MODULE, |
|
5143 |
functionLine, |
|
5144 |
Collections.<IdentNode>emptyList()); |
|
5145 |
lc.push(script); |
|
5146 |
||
5147 |
final ParserContextModuleNode module = new ParserContextModuleNode(moduleName); |
|
5148 |
lc.push(module); |
|
5149 |
||
5150 |
final ParserContextBlockNode body = newBlock(); |
|
5151 |
||
5152 |
functionDeclarations = new ArrayList<>(); |
|
5153 |
moduleBody(); |
|
5154 |
addFunctionDeclarations(script); |
|
5155 |
functionDeclarations = null; |
|
5156 |
||
5157 |
restoreBlock(body); |
|
5158 |
body.setFlag(Block.NEEDS_SCOPE); |
|
5159 |
final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); |
|
5160 |
lc.pop(module); |
|
5161 |
lc.pop(script); |
|
5162 |
script.setLastToken(token); |
|
5163 |
||
5164 |
expect(EOF); |
|
5165 |
||
5166 |
script.setModule(module.createModule()); |
|
5167 |
return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody); |
|
5168 |
} finally { |
|
5169 |
isStrictMode = oldStrictMode; |
|
5170 |
} |
|
5171 |
} |
|
5172 |
||
5173 |
/** |
|
5174 |
* Parse module body. |
|
5175 |
* |
|
5176 |
* ModuleBody : |
|
5177 |
* ModuleItemList |
|
5178 |
* |
|
5179 |
* ModuleItemList : |
|
5180 |
* ModuleItem |
|
5181 |
* ModuleItemList ModuleItem |
|
5182 |
* |
|
5183 |
* ModuleItem : |
|
5184 |
* ImportDeclaration |
|
5185 |
* ExportDeclaration |
|
5186 |
* StatementListItem |
|
5187 |
*/ |
|
5188 |
private void moduleBody() { |
|
5189 |
loop: |
|
5190 |
while (type != EOF) { |
|
5191 |
switch (type) { |
|
5192 |
case EOF: |
|
5193 |
break loop; |
|
5194 |
case IMPORT: |
|
5195 |
importDeclaration(); |
|
5196 |
break; |
|
5197 |
case EXPORT: |
|
5198 |
exportDeclaration(); |
|
5199 |
break; |
|
5200 |
default: |
|
5201 |
// StatementListItem |
|
39077
c549268fe94c
8156614: Lazy parsing of ES6 shorthand method syntax is broken
hannesw
parents:
38901
diff
changeset
|
5202 |
statement(true, 0, false, false); |
37732 | 5203 |
break; |
5204 |
} |
|
5205 |
} |
|
5206 |
} |
|
5207 |
||
5208 |
||
5209 |
/** |
|
5210 |
* Parse import declaration. |
|
5211 |
* |
|
5212 |
* ImportDeclaration : |
|
5213 |
* import ImportClause FromClause ; |
|
5214 |
* import ModuleSpecifier ; |
|
5215 |
* ImportClause : |
|
5216 |
* ImportedDefaultBinding |
|
5217 |
* NameSpaceImport |
|
5218 |
* NamedImports |
|
5219 |
* ImportedDefaultBinding , NameSpaceImport |
|
5220 |
* ImportedDefaultBinding , NamedImports |
|
5221 |
* ImportedDefaultBinding : |
|
5222 |
* ImportedBinding |
|
5223 |
* ModuleSpecifier : |
|
5224 |
* StringLiteral |
|
5225 |
* ImportedBinding : |
|
5226 |
* BindingIdentifier |
|
5227 |
*/ |
|
5228 |
private void importDeclaration() { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5229 |
final int startPosition = start; |
37732 | 5230 |
expect(IMPORT); |
5231 |
final ParserContextModuleNode module = lc.getCurrentModule(); |
|
5232 |
if (type == STRING || type == ESCSTRING) { |
|
5233 |
// import ModuleSpecifier ; |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5234 |
final IdentNode moduleSpecifier = createIdentNode(token, finish, (String) getValue()); |
37732 | 5235 |
next(); |
5236 |
module.addModuleRequest(moduleSpecifier); |
|
5237 |
} else { |
|
5238 |
// import ImportClause FromClause ; |
|
5239 |
List<Module.ImportEntry> importEntries; |
|
5240 |
if (type == MUL) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5241 |
importEntries = Collections.singletonList(nameSpaceImport(startPosition)); |
37732 | 5242 |
} else if (type == LBRACE) { |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5243 |
importEntries = namedImports(startPosition); |
37732 | 5244 |
} else if (isBindingIdentifier()) { |
5245 |
// ImportedDefaultBinding |
|
5246 |
final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding"); |
|
41422 | 5247 |
final Module.ImportEntry defaultImport = Module.ImportEntry.importSpecifier(importedDefaultBinding, startPosition, finish); |
37732 | 5248 |
|
5249 |
if (type == COMMARIGHT) { |
|
5250 |
next(); |
|
5251 |
importEntries = new ArrayList<>(); |
|
5252 |
if (type == MUL) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5253 |
importEntries.add(nameSpaceImport(startPosition)); |
37732 | 5254 |
} else if (type == LBRACE) { |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5255 |
importEntries.addAll(namedImports(startPosition)); |
37732 | 5256 |
} else { |
5257 |
throw error(AbstractParser.message("expected.named.import")); |
|
5258 |
} |
|
5259 |
} else { |
|
5260 |
importEntries = Collections.singletonList(defaultImport); |
|
5261 |
} |
|
5262 |
} else { |
|
5263 |
throw error(AbstractParser.message("expected.import")); |
|
5264 |
} |
|
5265 |
||
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5266 |
final IdentNode moduleSpecifier = fromClause(); |
37732 | 5267 |
module.addModuleRequest(moduleSpecifier); |
5268 |
for (int i = 0; i < importEntries.size(); i++) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5269 |
module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier, finish)); |
37732 | 5270 |
} |
5271 |
} |
|
5272 |
expect(SEMICOLON); |
|
5273 |
} |
|
5274 |
||
5275 |
/** |
|
5276 |
* NameSpaceImport : |
|
5277 |
* * as ImportedBinding |
|
5278 |
* |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5279 |
* @param startPosition the start of the import declaration |
37732 | 5280 |
* @return imported binding identifier |
5281 |
*/ |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5282 |
private Module.ImportEntry nameSpaceImport(final int startPosition) { |
37732 | 5283 |
assert type == MUL; |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5284 |
final IdentNode starName = createIdentNode(Token.recast(token, IDENT), finish, Module.STAR_NAME); |
37732 | 5285 |
next(); |
5286 |
final long asToken = token; |
|
5287 |
final String as = (String) expectValue(IDENT); |
|
5288 |
if (!"as".equals(as)) { |
|
5289 |
throw error(AbstractParser.message("expected.as"), asToken); |
|
5290 |
} |
|
5291 |
final IdentNode localNameSpace = bindingIdentifier("ImportedBinding"); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5292 |
return Module.ImportEntry.importSpecifier(starName, localNameSpace, startPosition, finish); |
37732 | 5293 |
} |
5294 |
||
5295 |
/** |
|
5296 |
* NamedImports : |
|
5297 |
* { } |
|
5298 |
* { ImportsList } |
|
5299 |
* { ImportsList , } |
|
5300 |
* ImportsList : |
|
5301 |
* ImportSpecifier |
|
5302 |
* ImportsList , ImportSpecifier |
|
5303 |
* ImportSpecifier : |
|
5304 |
* ImportedBinding |
|
5305 |
* IdentifierName as ImportedBinding |
|
5306 |
* ImportedBinding : |
|
5307 |
* BindingIdentifier |
|
5308 |
*/ |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5309 |
private List<Module.ImportEntry> namedImports(final int startPosition) { |
37732 | 5310 |
assert type == LBRACE; |
5311 |
next(); |
|
41422 | 5312 |
final List<Module.ImportEntry> importEntries = new ArrayList<>(); |
37732 | 5313 |
while (type != RBRACE) { |
5314 |
final boolean bindingIdentifier = isBindingIdentifier(); |
|
5315 |
final long nameToken = token; |
|
5316 |
final IdentNode importName = getIdentifierName(); |
|
5317 |
if (type == IDENT && "as".equals(getValue())) { |
|
5318 |
next(); |
|
5319 |
final IdentNode localName = bindingIdentifier("ImportedBinding"); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5320 |
importEntries.add(Module.ImportEntry.importSpecifier(importName, localName, startPosition, finish)); |
37732 | 5321 |
} else if (!bindingIdentifier) { |
5322 |
throw error(AbstractParser.message("expected.binding.identifier"), nameToken); |
|
5323 |
} else { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5324 |
importEntries.add(Module.ImportEntry.importSpecifier(importName, startPosition, finish)); |
37732 | 5325 |
} |
5326 |
if (type == COMMARIGHT) { |
|
5327 |
next(); |
|
5328 |
} else { |
|
5329 |
break; |
|
5330 |
} |
|
5331 |
} |
|
5332 |
expect(RBRACE); |
|
5333 |
return importEntries; |
|
5334 |
} |
|
5335 |
||
5336 |
/** |
|
5337 |
* FromClause : |
|
5338 |
* from ModuleSpecifier |
|
5339 |
*/ |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5340 |
private IdentNode fromClause() { |
37732 | 5341 |
final long fromToken = token; |
5342 |
final String name = (String) expectValue(IDENT); |
|
5343 |
if (!"from".equals(name)) { |
|
5344 |
throw error(AbstractParser.message("expected.from"), fromToken); |
|
5345 |
} |
|
5346 |
if (type == STRING || type == ESCSTRING) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5347 |
final IdentNode moduleSpecifier = createIdentNode(Token.recast(token, IDENT), finish, (String) getValue()); |
37732 | 5348 |
next(); |
5349 |
return moduleSpecifier; |
|
5350 |
} else { |
|
5351 |
throw error(expectMessage(STRING)); |
|
5352 |
} |
|
5353 |
} |
|
5354 |
||
5355 |
/** |
|
5356 |
* Parse export declaration. |
|
5357 |
* |
|
5358 |
* ExportDeclaration : |
|
5359 |
* export * FromClause ; |
|
5360 |
* export ExportClause FromClause ; |
|
5361 |
* export ExportClause ; |
|
5362 |
* export VariableStatement |
|
5363 |
* export Declaration |
|
5364 |
* export default HoistableDeclaration[Default] |
|
5365 |
* export default ClassDeclaration[Default] |
|
5366 |
* export default [lookahead !in {function, class}] AssignmentExpression[In] ; |
|
5367 |
*/ |
|
5368 |
private void exportDeclaration() { |
|
5369 |
expect(EXPORT); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5370 |
final int startPosition = start; |
37732 | 5371 |
final ParserContextModuleNode module = lc.getCurrentModule(); |
5372 |
switch (type) { |
|
5373 |
case MUL: { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5374 |
final IdentNode starName = createIdentNode(Token.recast(token, IDENT), finish, Module.STAR_NAME); |
37732 | 5375 |
next(); |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5376 |
final IdentNode moduleRequest = fromClause(); |
37732 | 5377 |
expect(SEMICOLON); |
5378 |
module.addModuleRequest(moduleRequest); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5379 |
module.addStarExportEntry(Module.ExportEntry.exportStarFrom(starName, moduleRequest, startPosition, finish)); |
37732 | 5380 |
break; |
5381 |
} |
|
5382 |
case LBRACE: { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5383 |
final List<Module.ExportEntry> exportEntries = exportClause(startPosition); |
37732 | 5384 |
if (type == IDENT && "from".equals(getValue())) { |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5385 |
final IdentNode moduleRequest = fromClause(); |
37732 | 5386 |
module.addModuleRequest(moduleRequest); |
41422 | 5387 |
for (final Module.ExportEntry exportEntry : exportEntries) { |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5388 |
module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest, finish)); |
37732 | 5389 |
} |
5390 |
} else { |
|
41422 | 5391 |
for (final Module.ExportEntry exportEntry : exportEntries) { |
37732 | 5392 |
module.addLocalExportEntry(exportEntry); |
5393 |
} |
|
5394 |
} |
|
5395 |
expect(SEMICOLON); |
|
5396 |
break; |
|
5397 |
} |
|
5398 |
case DEFAULT: |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5399 |
final IdentNode defaultName = createIdentNode(Token.recast(token, IDENT), finish, Module.DEFAULT_NAME); |
37732 | 5400 |
next(); |
5401 |
final Expression assignmentExpression; |
|
5402 |
IdentNode ident; |
|
5403 |
final int lineNumber = line; |
|
5404 |
final long rhsToken = token; |
|
5405 |
final boolean declaration; |
|
5406 |
switch (type) { |
|
5407 |
case FUNCTION: |
|
5408 |
assignmentExpression = functionExpression(false, true); |
|
5409 |
ident = ((FunctionNode) assignmentExpression).getIdent(); |
|
5410 |
declaration = true; |
|
5411 |
break; |
|
5412 |
case CLASS: |
|
5413 |
assignmentExpression = classDeclaration(true); |
|
5414 |
ident = ((ClassNode) assignmentExpression).getIdent(); |
|
5415 |
declaration = true; |
|
5416 |
break; |
|
5417 |
default: |
|
5418 |
assignmentExpression = assignmentExpression(false); |
|
5419 |
ident = null; |
|
5420 |
declaration = false; |
|
5421 |
break; |
|
5422 |
} |
|
5423 |
if (ident != null) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5424 |
module.addLocalExportEntry(Module.ExportEntry.exportDefault(defaultName, ident, startPosition, finish)); |
37732 | 5425 |
} else { |
5426 |
ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME); |
|
5427 |
lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression)); |
|
5428 |
if (!declaration) { |
|
5429 |
expect(SEMICOLON); |
|
5430 |
} |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5431 |
module.addLocalExportEntry(Module.ExportEntry.exportDefault(defaultName, ident, startPosition, finish)); |
37732 | 5432 |
} |
5433 |
break; |
|
5434 |
case VAR: |
|
5435 |
case LET: |
|
5436 |
case CONST: |
|
5437 |
final List<Statement> statements = lc.getCurrentBlock().getStatements(); |
|
5438 |
final int previousEnd = statements.size(); |
|
5439 |
variableStatement(type); |
|
5440 |
for (final Statement statement : statements.subList(previousEnd, statements.size())) { |
|
5441 |
if (statement instanceof VarNode) { |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5442 |
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName(), startPosition, finish)); |
37732 | 5443 |
} |
5444 |
} |
|
5445 |
break; |
|
5446 |
case CLASS: { |
|
5447 |
final ClassNode classDeclaration = classDeclaration(false); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5448 |
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent(), startPosition, finish)); |
37732 | 5449 |
break; |
5450 |
} |
|
5451 |
case FUNCTION: { |
|
5452 |
final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5453 |
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent(), startPosition, finish)); |
37732 | 5454 |
break; |
5455 |
} |
|
5456 |
default: |
|
5457 |
throw error(AbstractParser.message("invalid.export"), token); |
|
5458 |
} |
|
5459 |
} |
|
5460 |
||
5461 |
/** |
|
5462 |
* ExportClause : |
|
5463 |
* { } |
|
5464 |
* { ExportsList } |
|
5465 |
* { ExportsList , } |
|
5466 |
* ExportsList : |
|
5467 |
* ExportSpecifier |
|
5468 |
* ExportsList , ExportSpecifier |
|
5469 |
* ExportSpecifier : |
|
5470 |
* IdentifierName |
|
5471 |
* IdentifierName as IdentifierName |
|
5472 |
* |
|
5473 |
* @return a list of ExportSpecifiers |
|
5474 |
*/ |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5475 |
private List<Module.ExportEntry> exportClause(final int startPosition) { |
37732 | 5476 |
assert type == LBRACE; |
5477 |
next(); |
|
41422 | 5478 |
final List<Module.ExportEntry> exports = new ArrayList<>(); |
37732 | 5479 |
while (type != RBRACE) { |
5480 |
final IdentNode localName = getIdentifierName(); |
|
5481 |
if (type == IDENT && "as".equals(getValue())) { |
|
5482 |
next(); |
|
5483 |
final IdentNode exportName = getIdentifierName(); |
|
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5484 |
exports.add(Module.ExportEntry.exportSpecifier(exportName, localName, startPosition, finish)); |
37732 | 5485 |
} else { |
38901
28e775c6e08e
8159220: Preserve position info in module import and export entries
hannesw
parents:
38807
diff
changeset
|
5486 |
exports.add(Module.ExportEntry.exportSpecifier(localName, startPosition, finish)); |
37732 | 5487 |
} |
5488 |
if (type == COMMARIGHT) { |
|
5489 |
next(); |
|
5490 |
} else { |
|
5491 |
break; |
|
5492 |
} |
|
5493 |
} |
|
5494 |
expect(RBRACE); |
|
5495 |
return exports; |
|
5496 |
} |
|
5497 |
||
16252
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16245
diff
changeset
|
5498 |
@Override |
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16245
diff
changeset
|
5499 |
public String toString() { |
24759
31aed7d9c02a
8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents:
24751
diff
changeset
|
5500 |
return "'JavaScript Parsing'"; |
16252
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16245
diff
changeset
|
5501 |
} |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
5502 |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5503 |
private static void markEval(final ParserContext lc) { |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5504 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
17233 | 5505 |
boolean flaggedCurrentFn = false; |
5506 |
while (iter.hasNext()) { |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5507 |
final ParserContextFunctionNode fn = iter.next(); |
17233 | 5508 |
if (!flaggedCurrentFn) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5509 |
fn.setFlag(FunctionNode.HAS_EVAL); |
17233 | 5510 |
flaggedCurrentFn = true; |
37732 | 5511 |
if (fn.getKind() == FunctionNode.Kind.ARROW) { |
5512 |
// possible use of this in an eval that's nested in an arrow function, e.g.: |
|
5513 |
// function fun(){ return (() => eval("this"))(); }; |
|
5514 |
markThis(lc); |
|
5515 |
markNewTarget(lc); |
|
5516 |
} |
|
17233 | 5517 |
} else { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5518 |
fn.setFlag(FunctionNode.HAS_NESTED_EVAL); |
17233 | 5519 |
} |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5520 |
final ParserContextBlockNode body = lc.getFunctionBody(fn); |
26503 | 5521 |
// NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip |
5522 |
// parsing a nested function. functionBody() contains code to compensate for the lack of invoking |
|
5523 |
// this method when the parser skips a nested function. |
|
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5524 |
body.setFlag(Block.NEEDS_SCOPE); |
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5525 |
fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); |
17233 | 5526 |
} |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
5527 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
5528 |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
5529 |
private void prependStatement(final Statement statement) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5530 |
lc.prependStatementToCurrentNode(statement); |
17233 | 5531 |
} |
5532 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
5533 |
private void appendStatement(final Statement statement) { |
27102
c64b3468d51d
8012518: Reengineer Parser.java to make it play well with the copy-on-write IR.
lagergren
parents:
26646
diff
changeset
|
5534 |
lc.appendStatementToCurrentNode(statement); |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
5535 |
} |
37732 | 5536 |
|
5537 |
private static void markSuperCall(final ParserContext lc) { |
|
5538 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
5539 |
while (iter.hasNext()) { |
|
5540 |
final ParserContextFunctionNode fn = iter.next(); |
|
5541 |
if (fn.getKind() != FunctionNode.Kind.ARROW) { |
|
5542 |
assert fn.isSubclassConstructor(); |
|
5543 |
fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); |
|
5544 |
break; |
|
5545 |
} |
|
5546 |
} |
|
5547 |
} |
|
5548 |
||
5549 |
private ParserContextFunctionNode getCurrentNonArrowFunction() { |
|
5550 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
5551 |
while (iter.hasNext()) { |
|
5552 |
final ParserContextFunctionNode fn = iter.next(); |
|
5553 |
if (fn.getKind() != FunctionNode.Kind.ARROW) { |
|
5554 |
return fn; |
|
5555 |
} |
|
5556 |
} |
|
5557 |
return null; |
|
5558 |
} |
|
5559 |
||
5560 |
private static void markThis(final ParserContext lc) { |
|
5561 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
5562 |
while (iter.hasNext()) { |
|
5563 |
final ParserContextFunctionNode fn = iter.next(); |
|
5564 |
fn.setFlag(FunctionNode.USES_THIS); |
|
5565 |
if (fn.getKind() != FunctionNode.Kind.ARROW) { |
|
5566 |
break; |
|
5567 |
} |
|
5568 |
} |
|
5569 |
} |
|
5570 |
||
5571 |
private static void markNewTarget(final ParserContext lc) { |
|
5572 |
final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
5573 |
while (iter.hasNext()) { |
|
5574 |
final ParserContextFunctionNode fn = iter.next(); |
|
5575 |
if (fn.getKind() != FunctionNode.Kind.ARROW) { |
|
5576 |
if (!fn.isProgram()) { |
|
5577 |
fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET); |
|
5578 |
} |
|
5579 |
break; |
|
5580 |
} |
|
5581 |
} |
|
5582 |
} |
|
5583 |
||
5584 |
private boolean inGeneratorFunction() { |
|
5585 |
return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR; |
|
5586 |
} |
|
16147 | 5587 |
} |