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.ir.debug;
27
28 import java.util.Arrays;
29 import java.util.List;
30 import jdk.nashorn.internal.codegen.CompilerConstants;
31 import jdk.nashorn.internal.ir.AccessNode;
32 import jdk.nashorn.internal.ir.BinaryNode;
33 import jdk.nashorn.internal.ir.Block;
34 import jdk.nashorn.internal.ir.BlockStatement;
35 import jdk.nashorn.internal.ir.BreakNode;
36 import jdk.nashorn.internal.ir.CallNode;
37 import jdk.nashorn.internal.ir.CaseNode;
38 import jdk.nashorn.internal.ir.CatchNode;
39 import jdk.nashorn.internal.ir.ContinueNode;
40 import jdk.nashorn.internal.ir.EmptyNode;
41 import jdk.nashorn.internal.ir.ExpressionStatement;
42 import jdk.nashorn.internal.ir.ForNode;
43 import jdk.nashorn.internal.ir.FunctionNode;
44 import jdk.nashorn.internal.ir.IdentNode;
45 import jdk.nashorn.internal.ir.IfNode;
46 import jdk.nashorn.internal.ir.IndexNode;
47 import jdk.nashorn.internal.ir.LabelNode;
48 import jdk.nashorn.internal.ir.LexicalContext;
49 import jdk.nashorn.internal.ir.LiteralNode;
180 comma();
181
182 property("left");
183 binaryNode.lhs().accept(this);
184 comma();
185
186 property("right");
187 binaryNode.rhs().accept(this);
188
189 return leave();
190 }
191
192 @Override
193 public boolean enterBreakNode(final BreakNode breakNode) {
194 enterDefault(breakNode);
195
196 type("BreakStatement");
197 comma();
198
199 final IdentNode label = breakNode.getLabel();
200 if (label != null) {
201 property("label", label.getName());
202 } else {
203 property("label");
204 nullValue();
205 }
206
207 return leave();
208 }
209
210 @Override
211 public boolean enterCallNode(final CallNode callNode) {
212 enterDefault(callNode);
213
214 type("CallExpression");
215 comma();
216
217 property("callee");
218 callNode.getFunction().accept(this);
219 comma();
220
221 array("arguments", callNode.getArgs());
222
223 return leave();
239 }
240 comma();
241
242 array("consequent", caseNode.getBody().getStatements());
243
244 return leave();
245 }
246
247 @Override
248 public boolean enterCatchNode(final CatchNode catchNode) {
249 enterDefault(catchNode);
250
251 type("CatchClause");
252 comma();
253
254 property("param");
255 catchNode.getException().accept(this);
256 comma();
257
258 final Node guard = catchNode.getExceptionCondition();
259 property("guard");
260 if (guard != null) {
261 guard.accept(this);
262 } else {
263 nullValue();
264 }
265 comma();
266
267 property("body");
268 catchNode.getBody().accept(this);
269
270 return leave();
271 }
272
273 @Override
274 public boolean enterContinueNode(final ContinueNode continueNode) {
275 enterDefault(continueNode);
276
277 type("ContinueStatement");
278 comma();
279
280 final IdentNode label = continueNode.getLabel();
281 if (label != null) {
282 property("label", label.getName());
283 } else {
284 property("label");
285 nullValue();
286 }
287
288 return leave();
289 }
290
291 @Override
292 public boolean enterEmptyNode(final EmptyNode emptyNode) {
293 enterDefault(emptyNode);
294
295 type("EmptyStatement");
296
297 return leave();
298 }
299
300 @Override
301 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
302 enterDefault(expressionStatement);
303
304 type("ExpressionStatement");
305 comma();
306
307 property("expression");
308 expressionStatement.getExpression().accept(this);
309
310 return leave();
311 }
312
313 @Override
314 public boolean enterBlockStatement(BlockStatement blockStatement) {
315 enterDefault(blockStatement);
316
317 type("BlockStatement");
318 comma();
319
320 property("block");
321 blockStatement.getBlock().accept(this);
322
323 return leave();
324 }
325
326 @Override
327 public boolean enterForNode(final ForNode forNode) {
328 enterDefault(forNode);
371 comma();
372
373 final Node update = forNode.getModify();
374 property("update");
375 if (update != null) {
376 update.accept(this);
377 } else {
378 nullValue();
379 }
380 comma();
381
382 property("body");
383 forNode.getBody().accept(this);
384 }
385
386 return leave();
387 }
388
389 @Override
390 public boolean enterFunctionNode(final FunctionNode functionNode) {
391 enterDefault(functionNode);
392
393 final boolean program = functionNode.isProgram();
394 final String name;
395 if (program) {
396 name = "Program";
397 } else if (functionNode.isDeclared()) {
398 name = "FunctionDeclaration";
399 } else {
400 name = "FunctionExpression";
401 }
402 type(name);
403 comma();
404
405 if (! program) {
406 property("id");
407 if (functionNode.isAnonymous()) {
408 nullValue();
409 } else {
410 functionNode.getIdent().accept(this);
411 }
412 comma();
413 }
414
415 property("rest");
416 nullValue();
417 comma();
418
419 if (!program) {
420 array("params", functionNode.getParameters());
421 comma();
422 }
423
424 // body consists of nested functions and statements
425 final List<Statement> stats = functionNode.getBody().getStatements();
426 final int size = stats.size();
427 int idx = 0;
428 arrayStart("body");
429
430 for (final Node stat : stats) {
431 stat.accept(this);
432 if (idx != (size - 1)) {
433 comma();
434 }
435 idx++;
436 }
437 arrayEnd();
438
439 return leave();
440 }
441
442 @Override
443 public boolean enterIdentNode(final IdentNode identNode) {
713 type("ThrowStatement");
714 comma();
715
716 property("argument");
717 throwNode.getExpression().accept(this);
718
719 return leave();
720 }
721
722 @Override
723 public boolean enterTryNode(final TryNode tryNode) {
724 enterDefault(tryNode);
725
726 type("TryStatement");
727 comma();
728
729 property("block");
730 tryNode.getBody().accept(this);
731 comma();
732
733 array("handlers", tryNode.getCatches());
734 comma();
735
736 property("finalizer");
737 final Node finallyNode = tryNode.getFinallyBody();
738 if (finallyNode != null) {
739 finallyNode.accept(this);
740 } else {
741 nullValue();
742 }
743
744 return leave();
745 }
746
747 @Override
748 public boolean enterUnaryNode(final UnaryNode unaryNode) {
749 enterDefault(unaryNode);
750
751 final TokenType tokenType = unaryNode.tokenType();
752 if (tokenType == TokenType.NEW) {
753 type("NewExpression");
754 comma();
755
756 final CallNode callNode = (CallNode)unaryNode.rhs();
757 property("callee");
758 callNode.getFunction().accept(this);
759 comma();
760
761 array("arguments", callNode.getArgs());
762 } else {
763 final boolean prefix;
764 final String operator;
765 switch (tokenType) {
766 case INCPOSTFIX:
767 prefix = false;
768 operator = "++";
769 break;
770 case DECPOSTFIX:
771 prefix = false;
772 operator = "--";
773 break;
774 case INCPREFIX:
775 operator = "++";
776 prefix = true;
777 break;
778 case DECPREFIX:
779 operator = "--";
780 prefix = true;
781 break;
782 default:
783 prefix = false;
784 operator = tokenType.getName();
785 }
786
787 type(unaryNode.isAssignment()? "UpdateExpression" : "UnaryExpression");
788 comma();
789
790 property("operator", operator);
791 comma();
792
793 property("prefix", prefix);
794 comma();
795
796 property("argument");
797 unaryNode.rhs().accept(this);
798 }
799
800 return leave();
801 }
802
803 @Override
804 public boolean enterVarNode(final VarNode varNode) {
805 enterDefault(varNode);
806
807 type("VariableDeclaration");
808 comma();
809
810 arrayStart("declarations");
811
812 // VariableDeclarator
813 objectStart();
814 location(varNode.getName());
815
816 type("VariableDeclarator");
817 comma();
818
819 property("id", varNode.getName().toString());
820 comma();
821
822 property("init");
823 final Node init = varNode.getInit();
824 if (init != null) {
825 init.accept(this);
826 } else {
827 nullValue();
828 }
829
830 // VariableDeclarator
831 objectEnd();
832
833 // declarations
834 arrayEnd();
835
836 return leave();
837 }
838
839 @Override
840 public boolean enterWhileNode(final WhileNode whileNode) {
841 enterDefault(whileNode);
842
843 type(whileNode.isDoWhile() ? "DoWhileStatement" : "WhileStatement");
844 comma();
845
846 if (whileNode.isDoWhile()) {
847 property("body");
848 whileNode.getBody().accept(this);
849 comma();
850
851 property("test");
852 whileNode.getTest().accept(this);
853 } else {
854 property("test");
855 whileNode.getTest().accept(this);
856 comma();
857
858 property("block");
859 whileNode.getBody().accept(this);
860 }
861
862 return leave();
863 }
864
865 @Override
866 public boolean enterWithNode(final WithNode withNode) {
867 enterDefault(withNode);
868
869 type("WithStatement");
870 comma();
871
872 property("object");
873 withNode.getExpression().accept(this);
874 comma();
875
876 property("body");
877 withNode.getBody().accept(this);
878
879 return leave();
880 }
881
882 // Internals below
883
884 private JSONWriter(final boolean includeLocation) {
885 super(new LexicalContext());
886 this.buf = new StringBuilder();
887 this.includeLocation = includeLocation;
888 }
889
890 private final StringBuilder buf;
891 private final boolean includeLocation;
892
893 private String getString() {
894 return buf.toString();
895 }
896
897 private void property(final String key, final String value) {
898 buf.append('"');
899 buf.append(key);
900 buf.append("\":");
901 if (value != null) {
902 buf.append('"');
903 buf.append(value);
904 buf.append('"');
905 }
906 }
907
908 private void property(final String key, final boolean value) {
909 property(key, Boolean.toString(value));
910 }
911
912 private void property(final String key, final int value) {
913 property(key, Integer.toString(value));
914 }
915
916 private void property(final String key) {
917 property(key, null);
918 }
919
920 private void type(final String value) {
921 property("type", value);
922 }
923
924 private void objectStart(final String name) {
925 buf.append('"');
926 buf.append(name);
927 buf.append("\":{");
928 }
929
930 private void objectStart() {
931 buf.append('{');
932 }
933
|
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.ir.debug;
27
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.ArrayList;
31 import jdk.nashorn.internal.codegen.CompilerConstants;
32 import jdk.nashorn.internal.ir.AccessNode;
33 import jdk.nashorn.internal.ir.BinaryNode;
34 import jdk.nashorn.internal.ir.Block;
35 import jdk.nashorn.internal.ir.BlockStatement;
36 import jdk.nashorn.internal.ir.BreakNode;
37 import jdk.nashorn.internal.ir.CallNode;
38 import jdk.nashorn.internal.ir.CaseNode;
39 import jdk.nashorn.internal.ir.CatchNode;
40 import jdk.nashorn.internal.ir.ContinueNode;
41 import jdk.nashorn.internal.ir.EmptyNode;
42 import jdk.nashorn.internal.ir.ExpressionStatement;
43 import jdk.nashorn.internal.ir.ForNode;
44 import jdk.nashorn.internal.ir.FunctionNode;
45 import jdk.nashorn.internal.ir.IdentNode;
46 import jdk.nashorn.internal.ir.IfNode;
47 import jdk.nashorn.internal.ir.IndexNode;
48 import jdk.nashorn.internal.ir.LabelNode;
49 import jdk.nashorn.internal.ir.LexicalContext;
50 import jdk.nashorn.internal.ir.LiteralNode;
181 comma();
182
183 property("left");
184 binaryNode.lhs().accept(this);
185 comma();
186
187 property("right");
188 binaryNode.rhs().accept(this);
189
190 return leave();
191 }
192
193 @Override
194 public boolean enterBreakNode(final BreakNode breakNode) {
195 enterDefault(breakNode);
196
197 type("BreakStatement");
198 comma();
199
200 final IdentNode label = breakNode.getLabel();
201 property("label");
202 if (label != null) {
203 label.accept(this);
204 } else {
205 nullValue();
206 }
207
208 return leave();
209 }
210
211 @Override
212 public boolean enterCallNode(final CallNode callNode) {
213 enterDefault(callNode);
214
215 type("CallExpression");
216 comma();
217
218 property("callee");
219 callNode.getFunction().accept(this);
220 comma();
221
222 array("arguments", callNode.getArgs());
223
224 return leave();
240 }
241 comma();
242
243 array("consequent", caseNode.getBody().getStatements());
244
245 return leave();
246 }
247
248 @Override
249 public boolean enterCatchNode(final CatchNode catchNode) {
250 enterDefault(catchNode);
251
252 type("CatchClause");
253 comma();
254
255 property("param");
256 catchNode.getException().accept(this);
257 comma();
258
259 final Node guard = catchNode.getExceptionCondition();
260 if (guard != null) {
261 property("guard");
262 guard.accept(this);
263 comma();
264 }
265
266 property("body");
267 catchNode.getBody().accept(this);
268
269 return leave();
270 }
271
272 @Override
273 public boolean enterContinueNode(final ContinueNode continueNode) {
274 enterDefault(continueNode);
275
276 type("ContinueStatement");
277 comma();
278
279 final IdentNode label = continueNode.getLabel();
280 property("label");
281 if (label != null) {
282 label.accept(this);
283 } else {
284 nullValue();
285 }
286
287 return leave();
288 }
289
290 @Override
291 public boolean enterEmptyNode(final EmptyNode emptyNode) {
292 enterDefault(emptyNode);
293
294 type("EmptyStatement");
295
296 return leave();
297 }
298
299 @Override
300 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
301 // handle debugger statement
302 final Node expression = expressionStatement.getExpression();
303 if (expression instanceof RuntimeNode) {
304 expression.accept(this);
305 return false;
306 }
307
308 enterDefault(expressionStatement);
309
310 type("ExpressionStatement");
311 comma();
312
313 property("expression");
314 expression.accept(this);
315
316 return leave();
317 }
318
319 @Override
320 public boolean enterBlockStatement(BlockStatement blockStatement) {
321 enterDefault(blockStatement);
322
323 type("BlockStatement");
324 comma();
325
326 property("block");
327 blockStatement.getBlock().accept(this);
328
329 return leave();
330 }
331
332 @Override
333 public boolean enterForNode(final ForNode forNode) {
334 enterDefault(forNode);
377 comma();
378
379 final Node update = forNode.getModify();
380 property("update");
381 if (update != null) {
382 update.accept(this);
383 } else {
384 nullValue();
385 }
386 comma();
387
388 property("body");
389 forNode.getBody().accept(this);
390 }
391
392 return leave();
393 }
394
395 @Override
396 public boolean enterFunctionNode(final FunctionNode functionNode) {
397 final boolean program = functionNode.isProgram();
398 if (program) {
399 return emitProgram(functionNode);
400 }
401
402 enterDefault(functionNode);
403 final String name;
404 if (functionNode.isDeclared()) {
405 name = "FunctionDeclaration";
406 } else {
407 name = "FunctionExpression";
408 }
409 type(name);
410 comma();
411
412 property("id");
413 if (functionNode.isAnonymous()) {
414 nullValue();
415 } else {
416 functionNode.getIdent().accept(this);
417 }
418 comma();
419
420 array("params", functionNode.getParameters());
421 comma();
422
423 arrayStart("defaults");
424 arrayEnd();
425 comma();
426
427 property("rest");
428 nullValue();
429 comma();
430
431 property("body");
432 functionNode.getBody().accept(this);
433 comma();
434
435 property("generator", false);
436 comma();
437
438 property("expression", false);
439
440 return leave();
441 }
442
443 private boolean emitProgram(final FunctionNode functionNode) {
444 enterDefault(functionNode);
445 type("Program");
446 comma();
447
448 // body consists of nested functions and statements
449 final List<Statement> stats = functionNode.getBody().getStatements();
450 final int size = stats.size();
451 int idx = 0;
452 arrayStart("body");
453
454 for (final Node stat : stats) {
455 stat.accept(this);
456 if (idx != (size - 1)) {
457 comma();
458 }
459 idx++;
460 }
461 arrayEnd();
462
463 return leave();
464 }
465
466 @Override
467 public boolean enterIdentNode(final IdentNode identNode) {
737 type("ThrowStatement");
738 comma();
739
740 property("argument");
741 throwNode.getExpression().accept(this);
742
743 return leave();
744 }
745
746 @Override
747 public boolean enterTryNode(final TryNode tryNode) {
748 enterDefault(tryNode);
749
750 type("TryStatement");
751 comma();
752
753 property("block");
754 tryNode.getBody().accept(this);
755 comma();
756
757
758 final List<? extends Node> catches = tryNode.getCatches();
759 final List<CatchNode> guarded = new ArrayList<>();
760 CatchNode unguarded = null;
761 if (catches != null) {
762 for (Node n : catches) {
763 CatchNode cn = (CatchNode)n;
764 if (cn.getExceptionCondition() != null) {
765 guarded.add(cn);
766 } else {
767 assert unguarded == null: "too many unguarded?";
768 unguarded = cn;
769 }
770 }
771 }
772
773 array("guardedHandlers", guarded);
774 comma();
775
776 property("handler");
777 if (unguarded != null) {
778 unguarded.accept(this);
779 } else {
780 nullValue();
781 }
782 comma();
783
784 property("finalizer");
785 final Node finallyNode = tryNode.getFinallyBody();
786 if (finallyNode != null) {
787 finallyNode.accept(this);
788 } else {
789 nullValue();
790 }
791
792 return leave();
793 }
794
795 @Override
796 public boolean enterUnaryNode(final UnaryNode unaryNode) {
797 enterDefault(unaryNode);
798
799 final TokenType tokenType = unaryNode.tokenType();
800 if (tokenType == TokenType.NEW) {
801 type("NewExpression");
802 comma();
803
804 final CallNode callNode = (CallNode)unaryNode.rhs();
805 property("callee");
806 callNode.getFunction().accept(this);
807 comma();
808
809 array("arguments", callNode.getArgs());
810 } else {
811 final String operator;
812 final boolean prefix;
813 switch (tokenType) {
814 case INCPOSTFIX:
815 prefix = false;
816 operator = "++";
817 break;
818 case DECPOSTFIX:
819 prefix = false;
820 operator = "--";
821 break;
822 case INCPREFIX:
823 operator = "++";
824 prefix = true;
825 break;
826 case DECPREFIX:
827 operator = "--";
828 prefix = true;
829 break;
830 default:
831 prefix = true;
832 operator = tokenType.getName();
833 break;
834 }
835
836 type(unaryNode.isAssignment()? "UpdateExpression" : "UnaryExpression");
837 comma();
838
839 property("operator", operator);
840 comma();
841
842 property("prefix", prefix);
843 comma();
844
845 property("argument");
846 unaryNode.rhs().accept(this);
847 }
848
849 return leave();
850 }
851
852 @Override
853 public boolean enterVarNode(final VarNode varNode) {
854 final Node init = varNode.getInit();
855 if (init instanceof FunctionNode && ((FunctionNode)init).isDeclared()) {
856 // function declaration - don't emit VariableDeclaration instead
857 // just emit FunctionDeclaration using 'init' Node.
858 init.accept(this);
859 return false;
860 }
861
862 enterDefault(varNode);
863
864 type("VariableDeclaration");
865 comma();
866
867 arrayStart("declarations");
868
869 // VariableDeclarator
870 objectStart();
871 location(varNode.getName());
872
873 type("VariableDeclarator");
874 comma();
875
876 property("id");
877 varNode.getName().accept(this);
878 comma();
879
880 property("init");
881 if (init != null) {
882 init.accept(this);
883 } else {
884 nullValue();
885 }
886
887 // VariableDeclarator
888 objectEnd();
889
890 // declarations
891 arrayEnd();
892
893 return leave();
894 }
895
896 @Override
897 public boolean enterWhileNode(final WhileNode whileNode) {
898 enterDefault(whileNode);
899
900 type(whileNode.isDoWhile() ? "DoWhileStatement" : "WhileStatement");
901 comma();
902
903 if (whileNode.isDoWhile()) {
904 property("body");
905 whileNode.getBody().accept(this);
906 comma();
907
908 property("test");
909 whileNode.getTest().accept(this);
910 } else {
911 property("test");
912 whileNode.getTest().accept(this);
913 comma();
914
915 property("body");
916 whileNode.getBody().accept(this);
917 }
918
919 return leave();
920 }
921
922 @Override
923 public boolean enterWithNode(final WithNode withNode) {
924 enterDefault(withNode);
925
926 type("WithStatement");
927 comma();
928
929 property("object");
930 withNode.getExpression().accept(this);
931 comma();
932
933 property("body");
934 withNode.getBody().accept(this);
935
936 return leave();
937 }
938
939 // Internals below
940
941 private JSONWriter(final boolean includeLocation) {
942 super(new LexicalContext());
943 this.buf = new StringBuilder();
944 this.includeLocation = includeLocation;
945 }
946
947 private final StringBuilder buf;
948 private final boolean includeLocation;
949
950 private String getString() {
951 return buf.toString();
952 }
953
954 private void property(final String key, final String value, final boolean escape) {
955 buf.append('"');
956 buf.append(key);
957 buf.append("\":");
958 if (value != null) {
959 if (escape) buf.append('"');
960 buf.append(value);
961 if (escape) buf.append('"');
962 }
963 }
964
965 private void property(final String key, final String value) {
966 property(key, value, true);
967 }
968
969 private void property(final String key, final boolean value) {
970 property(key, Boolean.toString(value), false);
971 }
972
973 private void property(final String key, final int value) {
974 property(key, Integer.toString(value), false);
975 }
976
977 private void property(final String key) {
978 property(key, null);
979 }
980
981 private void type(final String value) {
982 property("type", value);
983 }
984
985 private void objectStart(final String name) {
986 buf.append('"');
987 buf.append(name);
988 buf.append("\":{");
989 }
990
991 private void objectStart() {
992 buf.append('{');
993 }
994
|