// Copyright (c) 2010 Per M.A. Bothner. // This is free software; for terms and warranty disclaimer see ../../COPYING. package gnu.expr; import gnu.text.SourceMessages; /** Class for doing a tree-visit over an Expression tree. */ public class ExpVisitor implements gnu.text.SourceLocator { protected SourceMessages messages; Compilation comp; /** Get the Compilation associated with this visitor. */ public Compilation getCompilation() { return comp; } public Language getLanguage() { return comp.getLanguage(); } public SourceMessages getMessages() { return messages; } protected R defaultValue(Expression r, D d) { return null; } protected R visitExpression(Expression exp, D d) { exp.visitChildren(this, d); return defaultValue(exp, d); } public void setContext(Compilation comp) { this.comp = comp; messages = comp.getMessages(); } /** Call the visit method of argument Expression. * Could call Expression's visit directly, but this allows us to * interpose a method call on each Expression. We use it to note the * Expression's line number. Should not need to be overridden; * if you do, you may also want to override visitExps. */ public R visit(Expression exp, D d) { return visit(this, exp, d); } public static R visit(ExpVisitor visitor, Expression exp, D d) { int line = exp.getLineNumber(); SourceMessages messages = visitor.messages; if (messages != null && line > 0) { String saveFile = messages.getFileName(); int saveLine = messages.getLineNumber(); int saveColumn = messages.getColumnNumber(); messages.setLine(exp.getFileName(), line, exp.getColumnNumber()); R ret = exp.visit(visitor, d); messages.setLine(saveFile, saveLine, saveColumn); return ret; } return exp.visit(visitor, d); } protected Expression update(Expression exp, R r) { return exp; } protected R visitApplyExp(ApplyExp exp, D d) { return visitExpression(exp, d); } protected R visitIfExp(IfExp exp, D d) { return visitExpression(exp, d); } protected R visitCaseExp(CaseExp exp, D d) { return visitExpression(exp, d); } protected void visitDeclarationType (Declaration decl) { Expression texp1 = decl.typeExp; if (texp1 != null) { Expression texp2 = visitAndUpdate(texp1, null); // FIXME if (texp2 != texp1) decl.setTypeExp(texp2); } } protected final void visitDeclarationTypes(ScopeExp exp) { for (Declaration decl = exp.firstDecl(); decl != null; decl = decl.nextDecl()) { visitDeclarationType(decl); } } protected R visitScopeExp(ScopeExp exp, D d) { visitDeclarationTypes(exp); return visitExpression(exp, d); } protected R visitLetExp(LetExp exp, D d) { return visitScopeExp(exp, d); } protected R visitLambdaExp(LambdaExp exp, D d) { return visitScopeExp(exp, d); } protected R visitClassExp(ClassExp exp, D d) { return visitLambdaExp(exp, d); } protected R visitObjectExp(ObjectExp exp, D d) { return visitClassExp(exp, d); } protected R visitModuleExp (ModuleExp exp, D d) { return visitLambdaExp(exp, d); } protected R visitSetExp(SetExp exp, D d) { exp.new_value = visitAndUpdate(exp.new_value, d); return defaultValue(exp, d); } //protected Expression visitSwitchExp (SwitchExp exp, D d) { return visitExpression(exp, d); } protected R visitTryExp(TryExp exp, D d) { return visitExpression(exp, d); } protected R visitBeginExp(BeginExp exp, D d) { return visitExpression(exp, d); } protected R visitQuoteExp(QuoteExp exp, D d) { return visitExpression(exp, d); } protected R visitReferenceExp(ReferenceExp exp, D d) { return visitExpression(exp, d); } protected R visitThisExp(ThisExp exp, D d) { return visitReferenceExp(exp, d); } protected R visitSynchronizedExp(SynchronizedExp exp, D d) { return visitExpression(exp, d); } protected R visitBlockExp(BlockExp exp, D d) { return visitExpression(exp, d); } protected R visitExitExp(ExitExp exp, D d) { return visitExpression(exp, d); } protected R visitFluidLetExp(FluidLetExp exp, D d) { return visitLetExp(exp, d); } protected R visitLangExp (LangExp exp, D d) { return visitExpression(exp, d); } protected LambdaExp currentLambda = null; /** If exitValue is set to non-null, the visit stops. */ protected Object exitValue = null; public Object getExitValue() { return exitValue; } public final LambdaExp getCurrentLambda() { return currentLambda; } public Expression visitAndUpdate(Expression exp, D d) { return update(exp, visit(exp, d)); } public Expression[] visitExps(Expression[] exps, D d) { return exps == null ? null : visitExps(exps, exps.length, d); } /** Call visit on the Expressions in an array. * However, the visit method is inlined for speed. */ public Expression[] visitExps(Expression[] exps, int n, D d) { for (int i = 0; i < n && exitValue == null; i++) exps[i] = visitAndUpdate(exps[i], d); return exps; } public void visitDefaultArgs(LambdaExp exp, D d) { for (Declaration p = exp.firstDecl(); p != null; p = p.nextDecl()) { Expression init = p.getInitValue(); if (init != null) p.setInitValue(visitAndUpdate(init, d)); } } public void error(char kind, String message) { if (kind == 'w' && comp.warnAsError()) kind = 'e'; if (messages != null) messages.error(kind, message); else new Error("internal error: "+message); } public Expression noteError(String message) { if (messages != null) messages.error('e', message); return new ErrorExp (message); } public final String getFileName() { return messages.getFileName(); } public final int getLineNumber() { return messages.getLineNumber(); } public final int getColumnNumber() { return messages.getColumnNumber(); } public final int getStartLine() { return messages.getStartLine(); } public final int getStartColumn() { return messages.getStartColumn(); } public final int getEndLine() { return messages.getEndLine(); } public final int getEndColumn() { return messages.getEndColumn(); } public String getPublicId() { return messages.getPublicId(); } public String getSystemId() { return messages.getSystemId(); } /** Normally same as getSystemId. */ public boolean isStableSourceLocation() { return false; } public void setFile(String filename) { messages.setFile(filename); } public void setLine(int line) { messages.setLine(line); } public void setColumn(int column) { messages.setColumn(column); } public void setLine(String filename, int line, int column) { messages.setLine(filename, line, column); } }