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