001: /*
002: * ScopeAnalyzer.java
003: *
004: * Copyright (c) 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.compiler;
010:
011: import pnuts.lang.*;
012: import pnuts.lang.Context;
013: import pnuts.lang.SimpleNode;
014: import pnuts.lang.Visitor;
015: import pnuts.lang.PnutsParserTreeConstants;
016: import java.io.Reader;
017: import java.io.IOException;
018:
019: public class ScopeAnalyzer implements Visitor {
020:
021: public Object start(SimpleNode node, Context context) {
022: return expressionList(node, context);
023: }
024:
025: public Object startSet(SimpleNode node, Context context) {
026: return expressionList(node, context);
027: }
028:
029: public Object expressionList(SimpleNode node, Context context) {
030: acceptChildren(node, context);
031: return null;
032: }
033:
034: /**
035: * If this metohd returns false, the node is not passed to handleFreeVariable() method
036: * even if the node represents a free variable.
037: */
038: protected boolean isTargetIdNode(SimpleNode node, Context context) {
039: return true;
040: }
041:
042: /**
043: * This method is called for each free variable, and supposed to be
044: * redefined by subclasses.
045: *
046: * @param node a SimpleNode that represents a free variable
047: * @param context the context
048: */
049: protected void handleFreeVariable(SimpleNode node, Context context) {
050: // skip
051: }
052:
053: /**
054: * This method is called for each local variable, and supposed to be
055: * redefined by subclasses.
056: *
057: * @param node a SimpleNode that represents a local variable
058: * @param context the context
059: */
060: protected void handleLocalVariable(SimpleNode node, Context context) {
061: // skip
062: }
063:
064: protected void declared(SimpleNode node, Context context,
065: String symbol) {
066: // skip
067: }
068:
069: public Object idNode(SimpleNode node, Context context) {
070: TranslateContext cc = (TranslateContext) context;
071: if (isTargetIdNode(node, cc)) {
072: Reference ref = cc.getReference(node.str);
073: if (ref == null) {
074: handleFreeVariable(node, cc);
075: } else {
076: handleLocalVariable(node, cc);
077: }
078: }
079: return null;
080: }
081:
082: public Object global(SimpleNode node, Context context) {
083: return null;
084: }
085:
086: public Object className(SimpleNode node, Context context) {
087: return null;
088: }
089:
090: public Object arrayType(SimpleNode node, Context context) {
091: acceptChildren(node, context);
092: return null;
093: }
094:
095: public Object castExpression(SimpleNode node, Context context) {
096: acceptChildren(node, context);
097: return null;
098: }
099:
100: public Object listElements(SimpleNode node, Context context) {
101: acceptChildren(node, context);
102: return null;
103: }
104:
105: public Object mapNode(SimpleNode node, Context context) {
106: int num = node.jjtGetNumChildren();
107: for (int i = 0; i < num; i++) {
108: SimpleNode c = node.jjtGetChild(i);
109: acceptChildren(c, context);
110: }
111: return null;
112: }
113:
114: public Object classNode(SimpleNode node, Context context) {
115: acceptChildren(node, context);
116: return null;
117: }
118:
119: public Object newNode(SimpleNode node, Context context) {
120: acceptChildren(node, context);
121: return null;
122: }
123:
124: public Object classDef(SimpleNode node, Context context) {
125: acceptChildren(node, context);
126: return null;
127: }
128:
129: public Object classDefBody(SimpleNode node, Context context) {
130: acceptChildren(node, context);
131: return null;
132: }
133:
134: public Object methodDef(SimpleNode node, Context context) {
135: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
136: if (info == null) {
137: node.setAttribute("frameInfo", info = new FrameInfo());
138: }
139: SimpleNode paramList;
140: SimpleNode c = node.jjtGetChild(0);
141: if (c.id == PnutsParserTreeConstants.JJTTYPEDPARAMLIST) {
142: paramList = c;
143: } else {
144: paramList = node.jjtGetChild(1);
145: }
146: int nargs = paramList.jjtGetNumChildren();
147: String[] locals = new String[nargs];
148: for (int i = 0; i < nargs; i++) {
149: SimpleNode param = paramList.jjtGetChild(i);
150: SimpleNode p = param.jjtGetChild(0);
151: if (p.id == PnutsParserTreeConstants.JJTCLASSNAME) {
152: locals[i] = param.jjtGetChild(1).str;
153: } else {
154: locals[i] = p.str;
155: }
156: }
157: String name = node.str;
158: TranslateContext cc = (TranslateContext) context;
159: cc.openFrame(name, locals);
160: acceptChildren(node, context);
161: info.freeVars = cc.getFreeVarSet();
162: cc.closeFrame();
163: info.preprocessed = true;
164: return null;
165: }
166:
167: public Object classScript(SimpleNode node, Context context) {
168: return null;
169: }
170:
171: public Object primitiveNode(SimpleNode node, Context context) {
172: return null;
173: }
174:
175: public Object packageNode(SimpleNode node, Context context) {
176: return null;
177: }
178:
179: public Object importNode(SimpleNode node, Context context) {
180: return null;
181: }
182:
183: public Object indexNode(SimpleNode node, Context context) {
184: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
185: if (info == null) {
186: node.setAttribute("frameInfo", new FrameInfo());
187: }
188: acceptChildren(node, context);
189: return null;
190: }
191:
192: public Object rangeNode(SimpleNode node, Context context) {
193: acceptChildren(node, context);
194: return null;
195: }
196:
197: public Object methodNode(SimpleNode node, Context context) {
198: acceptChildren(node, context);
199: return null;
200: }
201:
202: public Object staticMethodNode(SimpleNode node, Context context) {
203: acceptChildren(node, context);
204: return null;
205: }
206:
207: public Object memberNode(SimpleNode node, Context context) {
208: acceptChildren(node, context);
209: return null;
210: }
211:
212: public Object staticMemberNode(SimpleNode node, Context context) {
213: acceptChildren(node, context);
214: return null;
215: }
216:
217: public Object applicationNode(SimpleNode node, Context context) {
218: acceptChildren(node, context);
219: return null;
220: }
221:
222: public Object integerNode(SimpleNode node, Context context) {
223: return null;
224: }
225:
226: public Object floatingNode(SimpleNode node, Context context) {
227: return null;
228: }
229:
230: public Object characterNode(SimpleNode node, Context context) {
231: return null;
232: }
233:
234: public Object stringNode(SimpleNode node, Context context) {
235: acceptChildren(node, context);
236: return null;
237: }
238:
239: public Object trueNode(SimpleNode node, Context context) {
240: return null;
241: }
242:
243: public Object falseNode(SimpleNode node, Context context) {
244: return null;
245: }
246:
247: public Object nullNode(SimpleNode node, Context context) {
248: return null;
249: }
250:
251: public Object assignment(SimpleNode node, Context context) {
252: node.jjtGetChild(1).accept(this , context);
253: SimpleNode lhs = node.jjtGetChild(0);
254: if (lhs.id == PnutsParserTreeConstants.JJTIDNODE) {
255: assignId(lhs, context);
256: } else {
257: lhs.accept(this , context);
258: }
259: return null;
260: }
261:
262: public Object assignmentTA(SimpleNode node, Context context) {
263: acceptChildren(node.jjtGetChild(1), context);
264: return null;
265: }
266:
267: public Object assignmentMA(SimpleNode node, Context context) {
268: acceptChildren(node.jjtGetChild(1), context);
269: return null;
270: }
271:
272: public Object assignmentDA(SimpleNode node, Context context) {
273: acceptChildren(node.jjtGetChild(1), context);
274: return null;
275: }
276:
277: public Object assignmentPA(SimpleNode node, Context context) {
278: acceptChildren(node.jjtGetChild(1), context);
279: return null;
280: }
281:
282: public Object assignmentSA(SimpleNode node, Context context) {
283: acceptChildren(node.jjtGetChild(1), context);
284: return null;
285: }
286:
287: public Object assignmentLA(SimpleNode node, Context context) {
288: acceptChildren(node.jjtGetChild(1), context);
289: return null;
290: }
291:
292: public Object assignmentRA(SimpleNode node, Context context) {
293: acceptChildren(node.jjtGetChild(1), context);
294: return null;
295: }
296:
297: public Object assignmentRAA(SimpleNode node, Context context) {
298: acceptChildren(node.jjtGetChild(1), context);
299: return null;
300: }
301:
302: public Object assignmentAA(SimpleNode node, Context context) {
303: acceptChildren(node.jjtGetChild(1), context);
304: return null;
305: }
306:
307: public Object assignmentEA(SimpleNode node, Context context) {
308: acceptChildren(node.jjtGetChild(1), context);
309: return null;
310: }
311:
312: public Object assignmentOA(SimpleNode node, Context context) {
313: acceptChildren(node.jjtGetChild(1), context);
314: return null;
315: }
316:
317: public Object orNode(SimpleNode node, Context context) {
318: acceptChildren(node, context);
319: return null;
320: }
321:
322: public Object andNode(SimpleNode node, Context context) {
323: acceptChildren(node, context);
324: return null;
325: }
326:
327: public Object xorNode(SimpleNode node, Context context) {
328: acceptChildren(node, context);
329: return null;
330: }
331:
332: public Object logAndNode(SimpleNode node, Context context) {
333: acceptChildren(node, context);
334: return null;
335: }
336:
337: public Object logOrNode(SimpleNode node, Context context) {
338: acceptChildren(node, context);
339: return null;
340: }
341:
342: public Object logNotNode(SimpleNode node, Context context) {
343: acceptChildren(node, context);
344: return null;
345: }
346:
347: public Object equalNode(SimpleNode node, Context context) {
348: acceptChildren(node, context);
349: return null;
350: }
351:
352: public Object notEqNode(SimpleNode node, Context context) {
353: acceptChildren(node, context);
354: return null;
355: }
356:
357: public Object instanceof Expression(SimpleNode node, Context context) {
358: acceptChildren(node, context);
359: return null;
360: }
361:
362: public Object ltNode(SimpleNode node, Context context) {
363: acceptChildren(node, context);
364: return null;
365: }
366:
367: public Object gtNode(SimpleNode node, Context context) {
368: acceptChildren(node, context);
369: return null;
370: }
371:
372: public Object leNode(SimpleNode node, Context context) {
373: acceptChildren(node, context);
374: return null;
375: }
376:
377: public Object geNode(SimpleNode node, Context context) {
378: acceptChildren(node, context);
379: return null;
380: }
381:
382: public Object shiftLeftNode(SimpleNode node, Context context) {
383: acceptChildren(node, context);
384: return null;
385: }
386:
387: public Object shiftRightNode(SimpleNode node, Context context) {
388: acceptChildren(node, context);
389: return null;
390: }
391:
392: public Object shiftArithmeticNode(SimpleNode node, Context context) {
393: acceptChildren(node, context);
394: return null;
395: }
396:
397: public Object addNode(SimpleNode node, Context context) {
398: acceptChildren(node, context);
399: return null;
400: }
401:
402: public Object subtractNode(SimpleNode node, Context context) {
403: acceptChildren(node, context);
404: return null;
405: }
406:
407: public Object multNode(SimpleNode node, Context context) {
408: acceptChildren(node, context);
409: return null;
410: }
411:
412: public Object divideNode(SimpleNode node, Context context) {
413: acceptChildren(node, context);
414: return null;
415: }
416:
417: public Object modNode(SimpleNode node, Context context) {
418: acceptChildren(node, context);
419: return null;
420: }
421:
422: public Object negativeNode(SimpleNode node, Context context) {
423: acceptChildren(node, context);
424: return null;
425: }
426:
427: public Object preIncrNode(SimpleNode node, Context context) {
428: acceptChildren(node, context);
429: return null;
430: }
431:
432: public Object preDecrNode(SimpleNode node, Context context) {
433: acceptChildren(node, context);
434: return null;
435: }
436:
437: public Object notNode(SimpleNode node, Context context) {
438: acceptChildren(node, context);
439: return null;
440: }
441:
442: public Object postIncrNode(SimpleNode node, Context context) {
443: acceptChildren(node, context);
444: return null;
445: }
446:
447: public Object postDecrNode(SimpleNode node, Context context) {
448: acceptChildren(node, context);
449: return null;
450: }
451:
452: public Object breakNode(SimpleNode node, Context context) {
453: acceptChildren(node, context);
454: return null;
455: }
456:
457: public Object continueNode(SimpleNode node, Context context) {
458: acceptChildren(node, context);
459: return null;
460: }
461:
462: public Object returnNode(SimpleNode node, Context context) {
463: acceptChildren(node, context);
464: return null;
465: }
466:
467: public Object yieldNode(SimpleNode node, Context context) {
468: acceptChildren(node, context);
469: return null;
470: }
471:
472: public Object tryStatement(SimpleNode node, Context context) {
473: acceptChildren(node, context);
474: return null;
475: }
476:
477: public Object catchBlock(SimpleNode node, Context context) {
478: acceptChildren(node, context);
479: return null;
480: }
481:
482: public Object finallyBlock(SimpleNode node, Context context) {
483: acceptChildren(node, context);
484: return null;
485: }
486:
487: public Object blockNode(SimpleNode node, Context context) {
488: acceptChildren(node, context);
489: return null;
490: }
491:
492: public Object ifStatement(SimpleNode node, Context context) {
493: TranslateContext cc = (TranslateContext) context;
494: SimpleNode condNode = node.jjtGetChild(0);
495: condNode.accept(this , context);
496: cc.openBranchEnv();
497: node.jjtGetChild(1).accept(this , context);
498:
499: int n = node.jjtGetNumChildren();
500: for (int i = 2; i < n; i++) {
501: SimpleNode _node = node.jjtGetChild(i);
502: if (_node.id == PnutsParserTreeConstants.JJTELSEIFNODE) {
503: cc.addBranch();
504: SimpleNode _condNode = _node.jjtGetChild(0);
505: _condNode.accept(this , context);
506: _node.jjtGetChild(1).accept(this , context);
507: } else if (_node.id == PnutsParserTreeConstants.JJTELSENODE) {
508: cc.addBranch();
509: _node.jjtGetChild(0).accept(this , context);
510:
511: }
512: }
513: cc.closeBranchEnv();
514: return null;
515: }
516:
517: public Object doStatement(SimpleNode node, Context context) {
518: acceptChildren(node, context);
519: return null;
520: }
521:
522: public Object whileStatement(SimpleNode node, Context context) {
523: acceptChildren(node, context);
524: return null;
525: }
526:
527: public Object forStatement(SimpleNode node, Context context) {
528: int j = 0;
529: SimpleNode n = node.jjtGetChild(j);
530:
531: TranslateContext cc = (TranslateContext) context;
532: SimpleNode blockNode = null;
533: if (n.id == PnutsParserTreeConstants.JJTFORENUM) {
534: SimpleNode n0 = n.jjtGetChild(0);
535:
536: if (n0.id == PnutsParserTreeConstants.JJTMULTIASSIGNLHS) {
537: n.jjtGetChild(1).accept(this , context);
538: int num = n0.jjtGetNumChildren();
539: String[] vars = new String[num];
540: for (int i = 0; i < num; i++) {
541: vars[i] = n0.jjtGetChild(i).str;
542: }
543: cc.openScope(vars);
544: blockNode = node.jjtGetChild(1);
545: acceptChildren(blockNode, context);
546: cc.closeScope();
547:
548: return null;
549: }
550:
551: int num = n.jjtGetNumChildren();
552: for (int i = 0; i < num; i++) {
553: n.jjtGetChild(i).accept(this , context);
554: }
555:
556: int nc = n.jjtGetNumChildren();
557: blockNode = node.jjtGetChild(1);
558: if (nc == 1 || nc == 2) { // for (i : value) or for (i : start .. end)
559: cc.openScope(new String[] { n.str });
560: acceptChildren(blockNode, context);
561: cc.closeScope();
562: } else {
563: return null;
564: }
565:
566: } else { // for (;;)
567:
568: String[] env;
569: if (n.id == PnutsParserTreeConstants.JJTFORINIT) {
570: int _num = n.jjtGetNumChildren();
571: env = new String[_num];
572: for (int i = 0; i < _num; i++) {
573: SimpleNode sn = n.jjtGetChild(i);
574: sn.jjtGetChild(0).accept(this , context);
575: env[i] = sn.str;
576: }
577: j++;
578: } else {
579: env = new String[0];
580: }
581: cc.openScope(env);
582:
583: n = node.jjtGetChild(j);
584: if (n.id != PnutsParserTreeConstants.JJTFORUPDATE
585: && n.id != PnutsParserTreeConstants.JJTBLOCK) {
586: n.accept(this , context);
587: j++;
588: }
589: n = node.jjtGetChild(j);
590: if (n.id == PnutsParserTreeConstants.JJTFORUPDATE) {
591: n.jjtGetChild(0).accept(this , context);
592: j++;
593: }
594:
595: blockNode = node.jjtGetChild(j);
596: acceptChildren(blockNode, context);
597: cc.closeScope();
598: }
599: return null;
600: }
601:
602: public Object foreachStatement(SimpleNode node, Context context) {
603: TranslateContext cc = (TranslateContext) context;
604: cc.openScope(new String[] { node.str });
605: SimpleNode listNode = node.jjtGetChild(0);
606: SimpleNode blockNode = node.jjtGetChild(1);
607: acceptChildren(listNode, context);
608: acceptChildren(blockNode, context);
609: cc.closeScope();
610: return null;
611: }
612:
613: public Object switchStatement(SimpleNode node, Context context) {
614: int num = node.jjtGetNumChildren();
615: for (int i = 0; i < num; i++) {
616: SimpleNode c = node.jjtGetChild(i);
617: if (c.id == PnutsParserTreeConstants.JJTSWITCHLABEL) {
618: if (c.jjtGetNumChildren() > 0) {
619: c.jjtGetChild(0).accept(this , context);
620: }
621: } else {
622: c.accept(this , context);
623: }
624: }
625: return null;
626: }
627:
628: public Object switchBlock(SimpleNode node, Context context) {
629: acceptChildren(node, context);
630: return null;
631: }
632:
633: public Object functionStatement(SimpleNode node, Context context) {
634: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
635: if (info == null) {
636: node.setAttribute("frameInfo", info = new FrameInfo());
637: }
638: TranslateContext cc = (TranslateContext) context;
639: String name = node.str;
640: SimpleNode block = node.jjtGetChild(1);
641: SimpleNode param = node.jjtGetChild(0);
642: int nargs = param.jjtGetNumChildren();
643: String[] locals = new String[nargs];
644: SimpleNode n0 = null;
645: if (nargs == 1
646: && (n0 = param.jjtGetChild(0)).id == PnutsParserTreeConstants.JJTINDEXNODE) {
647: nargs = -1;
648: locals[0] = n0.jjtGetChild(0).str;
649: } else {
650: for (int j = 0; j < nargs; j++) {
651: locals[j] = param.jjtGetChild(j).str;
652: }
653: }
654: if (cc.env.parent != null && name != null) {
655: cc.declare(name);
656: }
657: cc.openFrame(name, locals);
658: block.accept(this , context);
659:
660: // ((FrameInfo)node.info).freeVars = cc.getFreeVarSet();
661: info.freeVars = cc.getFreeVarSet();
662:
663: cc.closeFrame();
664:
665: // ((FrameInfo)node.info).preprocessed = true;
666: info.preprocessed = true;
667: return null;
668: }
669:
670: public Object ternary(SimpleNode node, Context context) {
671: acceptChildren(node, context);
672: return null;
673: }
674:
675: public Object catchNode(SimpleNode node, Context context) {
676: acceptChildren(node, context);
677: return null;
678: }
679:
680: public Object throwNode(SimpleNode node, Context context) {
681: acceptChildren(node, context);
682: return null;
683: }
684:
685: public Object finallyNode(SimpleNode node, Context context) {
686: acceptChildren(node, context);
687: return null;
688: }
689:
690: public Object beanDef(SimpleNode node, Context context) {
691: acceptChildren(node, context);
692: return null;
693: }
694:
695: void assignId(SimpleNode lhs, Context context) {
696: String symbol = lhs.str;
697: TranslateContext cc = (TranslateContext) context;
698: Reference ref = cc.getReference(symbol);
699: if (cc.env.parent != null) {
700: if (ref == null) {
701: cc.declare(symbol);
702: declared(lhs, context, symbol);
703: }
704: }
705: }
706:
707: void acceptChildren(SimpleNode node, Context context) {
708: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
709: if (info == null) {
710: node.setAttribute("frameInfo", new FrameInfo());
711: }
712: int num = node.jjtGetNumChildren();
713: for (int i = 0; i < num; i++) {
714: node.jjtGetChild(i).accept(this , context);
715: }
716: }
717:
718: /**
719: * Analyzes a script
720: */
721: public void analyze(Reader reader) throws ParseException,
722: IOException {
723: analyze(new PnutsParser(reader));
724: }
725:
726: public void analyze(PnutsParser parser) throws ParseException,
727: IOException {
728: parser.StartSet(null).accept(this , new TranslateContext());
729: }
730:
731: public void analyze(SimpleNode node) {
732: node.accept(this , new TranslateContext());
733: }
734:
735: public static void main(String[] args) throws Exception {
736: ScopeAnalyzer analyzer = new ScopeAnalyzer() {
737: protected void handleFreeVariable(SimpleNode node,
738: Context context) {
739: System.out.println("free: " + node.str + ", "
740: + node.beginLine);
741: }
742:
743: protected void handleLocalVariable(SimpleNode node,
744: Context context) {
745: System.out.println("local: " + node.str + ", "
746: + node.beginLine);
747: }
748: };
749: analyzer.analyze(new java.io.FileReader(args[0]));
750: }
751: }
|