1 // Copyright (c) 2010  Per M.A. Bothner.
2 // This is free software; for terms and warranty disclaimer see ../../COPYING.
3 
4 package gnu.expr;
5 import gnu.text.SourceMessages;
6 
7 /** Class for doing a tree-visit over an Expression tree. */
8 
9 public class ExpVisitor<R,D>
10         implements gnu.text.SourceLocator {
11     protected SourceMessages messages;
12     Compilation comp;
13 
14     /** Get the Compilation associated with this visitor. */
getCompilation()15     public Compilation getCompilation() { return comp; }
16 
getLanguage()17     public Language getLanguage() { return comp.getLanguage(); }
18 
getMessages()19     public SourceMessages getMessages() { return messages; }
20 
defaultValue(Expression r, D d)21     protected R defaultValue(Expression r, D d) {
22         return null;
23     }
24 
visitExpression(Expression exp, D d)25     protected R visitExpression(Expression exp, D d) {
26         exp.visitChildren(this, d);
27         return defaultValue(exp, d);
28     }
29 
setContext(Compilation comp)30     public void setContext(Compilation comp) {
31         this.comp = comp;
32         messages = comp.getMessages();
33     }
34 
35     /** Call the visit method of argument Expression.
36      * Could call Expression's visit directly, but this allows us to
37      * interpose a method call on each Expression.  We use it to note the
38      * Expression's line number.  Should not need to be overridden;
39      * if you do, you may also want to override visitExps. */
visit(Expression exp, D d)40     public R visit(Expression exp, D d) {
41         return visit(this, exp, d);
42     }
43 
visit(ExpVisitor<R,D> visitor, Expression exp, D d)44     public static <R,D> R visit(ExpVisitor<R,D> visitor, Expression exp, D d) {
45         int line = exp.getLineNumber();
46         SourceMessages messages = visitor.messages;
47         if (messages != null && line > 0) {
48             String saveFile = messages.getFileName();
49             int saveLine = messages.getLineNumber();
50             int saveColumn = messages.getColumnNumber();
51             messages.setLine(exp.getFileName(), line, exp.getColumnNumber());
52             R ret = exp.visit(visitor, d);
53             messages.setLine(saveFile, saveLine, saveColumn);
54             return ret;
55         }
56         return exp.visit(visitor, d);
57     }
58 
update(Expression exp, R r)59     protected Expression update(Expression exp, R r) {
60         return exp;
61     }
62 
visitApplyExp(ApplyExp exp, D d)63     protected R visitApplyExp(ApplyExp exp, D d) {
64         return visitExpression(exp, d);
65     }
66 
visitIfExp(IfExp exp, D d)67     protected R visitIfExp(IfExp exp, D d) {
68         return visitExpression(exp, d);
69     }
70 
visitCaseExp(CaseExp exp, D d)71     protected R visitCaseExp(CaseExp exp, D d) {
72         return visitExpression(exp, d);
73     }
74 
visitDeclarationType(Declaration decl)75     protected void visitDeclarationType (Declaration decl)
76     {
77         Expression texp1 = decl.typeExp;
78         if (texp1 != null) {
79             Expression texp2 = visitAndUpdate(texp1, null); // FIXME
80             if (texp2 != texp1)
81                 decl.setTypeExp(texp2);
82         }
83     }
84 
visitDeclarationTypes(ScopeExp exp)85     protected final void visitDeclarationTypes(ScopeExp exp) {
86         for (Declaration decl = exp.firstDecl(); decl != null;
87              decl = decl.nextDecl()) {
88             visitDeclarationType(decl);
89         }
90     }
91 
visitScopeExp(ScopeExp exp, D d)92     protected R visitScopeExp(ScopeExp exp, D d) {
93         visitDeclarationTypes(exp);
94         return visitExpression(exp, d);
95     }
96 
visitLetExp(LetExp exp, D d)97     protected R visitLetExp(LetExp exp, D d) { return visitScopeExp(exp, d); }
visitLambdaExp(LambdaExp exp, D d)98     protected R visitLambdaExp(LambdaExp exp, D d) { return visitScopeExp(exp, d); }
visitClassExp(ClassExp exp, D d)99     protected R visitClassExp(ClassExp exp, D d) { return visitLambdaExp(exp, d); }
visitObjectExp(ObjectExp exp, D d)100     protected R visitObjectExp(ObjectExp exp, D d) { return visitClassExp(exp, d); }
visitModuleExp(ModuleExp exp, D d)101     protected R visitModuleExp (ModuleExp exp, D d) { return visitLambdaExp(exp, d); }
102 
visitSetExp(SetExp exp, D d)103     protected R visitSetExp(SetExp exp, D d) {
104         exp.new_value = visitAndUpdate(exp.new_value, d);
105         return defaultValue(exp, d);
106     }
107 
108     //protected Expression visitSwitchExp (SwitchExp exp, D d) { return visitExpression(exp, d); }
visitTryExp(TryExp exp, D d)109     protected R visitTryExp(TryExp exp, D d) { return visitExpression(exp, d); }
visitBeginExp(BeginExp exp, D d)110     protected R visitBeginExp(BeginExp exp, D d) { return visitExpression(exp, d); }
visitQuoteExp(QuoteExp exp, D d)111     protected R visitQuoteExp(QuoteExp exp, D d) { return visitExpression(exp, d); }
visitReferenceExp(ReferenceExp exp, D d)112     protected R visitReferenceExp(ReferenceExp exp, D d) {
113         return visitExpression(exp, d);
114     }
visitThisExp(ThisExp exp, D d)115     protected R visitThisExp(ThisExp exp, D d) {
116         return visitReferenceExp(exp, d);
117     }
visitSynchronizedExp(SynchronizedExp exp, D d)118     protected R visitSynchronizedExp(SynchronizedExp exp, D d)
119     { return visitExpression(exp, d); }
120 
visitBlockExp(BlockExp exp, D d)121     protected R visitBlockExp(BlockExp exp, D d) { return visitExpression(exp, d); }
visitExitExp(ExitExp exp, D d)122     protected R visitExitExp(ExitExp exp, D d) { return visitExpression(exp, d); }
visitFluidLetExp(FluidLetExp exp, D d)123     protected R visitFluidLetExp(FluidLetExp exp, D d) {
124         return visitLetExp(exp, d);
125     }
visitLangExp(LangExp exp, D d)126     protected R visitLangExp (LangExp exp, D d)
127     { return visitExpression(exp, d); }
128 
129     protected LambdaExp currentLambda = null;
130 
131     /** If exitValue is set to non-null, the visit stops. */
132     protected Object exitValue = null;
133 
getExitValue()134     public Object getExitValue() { return exitValue; }
135 
getCurrentLambda()136     public final LambdaExp getCurrentLambda() { return currentLambda; }
137 
visitAndUpdate(Expression exp, D d)138     public Expression visitAndUpdate(Expression exp, D d) {
139         return update(exp, visit(exp, d));
140     }
141 
visitExps(Expression[] exps, D d)142     public Expression[] visitExps(Expression[] exps, D d) {
143         return exps == null ? null : visitExps(exps, exps.length, d);
144     }
145 
146     /** Call visit on the Expressions in an array.
147      * However, the visit method is inlined for speed.
148      */
visitExps(Expression[] exps, int n, D d)149     public Expression[] visitExps(Expression[] exps, int n, D d) {
150         for (int i = 0;  i < n && exitValue == null;  i++)
151             exps[i] = visitAndUpdate(exps[i], d);
152         return exps;
153     }
154 
visitDefaultArgs(LambdaExp exp, D d)155     public void visitDefaultArgs(LambdaExp exp, D d) {
156         for (Declaration p = exp.firstDecl(); p != null; p = p.nextDecl()) {
157             Expression init = p.getInitValue();
158             if (init != null)
159                 p.setInitValue(visitAndUpdate(init, d));
160         }
161     }
162 
error(char kind, String message)163     public void error(char kind, String message) {
164         if (kind == 'w' && comp.warnAsError())
165             kind = 'e';
166         if (messages != null)
167             messages.error(kind, message);
168         else
169             new Error("internal error: "+message);
170     }
171 
noteError(String message)172     public Expression noteError(String message) {
173         if (messages != null)
174             messages.error('e', message);
175         return new ErrorExp (message);
176     }
177 
getFileName()178     public final String getFileName() { return messages.getFileName(); }
getLineNumber()179     public final int getLineNumber() { return messages.getLineNumber(); }
getColumnNumber()180     public final int getColumnNumber() { return messages.getColumnNumber(); }
getStartLine()181     public final int getStartLine()  { return messages.getStartLine(); }
getStartColumn()182     public final int getStartColumn()  { return messages.getStartColumn(); }
getEndLine()183     public final int getEndLine()  { return messages.getEndLine(); }
getEndColumn()184     public final int getEndColumn()  { return messages.getEndColumn(); }
getPublicId()185     public String getPublicId() { return messages.getPublicId(); }
getSystemId()186     public String getSystemId() { return messages.getSystemId(); }
187     /** Normally same as getSystemId. */
188 
isStableSourceLocation()189     public boolean isStableSourceLocation() { return false; }
190 
setFile(String filename)191     public void setFile(String filename) { messages.setFile(filename); }
setLine(int line)192     public void setLine(int line) { messages.setLine(line); }
setColumn(int column)193     public void setColumn(int column) { messages.setColumn(column); }
194 
setLine(String filename, int line, int column)195     public void setLine(String filename, int line, int column) {
196         messages.setLine(filename, line, column);
197     }
198 }
199