1 package gnu.expr;
2 import gnu.bytecode.*;
3 import gnu.kawa.io.OutPort;
4 import gnu.mapping.CallContext;
5 
6 /**
7   * This class represents try/catch/finally.
8   * @author      Per Bothner
9   */
10 
11 public class TryExp extends Expression
12 {
13   Expression try_clause;
14 
15   CatchClause catch_clauses;
16 
17   Expression finally_clause;
18 
getCatchClauses()19   public final CatchClause getCatchClauses () { return catch_clauses; }
getFinallyClause()20   public final Expression getFinallyClause () { return finally_clause; }
setCatchClauses(CatchClause catch_clauses)21   public final void setCatchClauses (CatchClause catch_clauses)
22   {
23     this.catch_clauses = catch_clauses;
24   }
25 
addCatchClause(Declaration decl, Expression body)26     public void addCatchClause(Declaration decl, Expression body) {
27         CatchClause clause = new CatchClause(decl, body);
28         CatchClause last = catch_clauses;
29         if (last == null)
30             catch_clauses = clause;
31         else {
32             while (last.next != null)
33                 last = last.next;
34             last.next = clause;
35         }
36     }
37 
TryExp(Expression try_clause, Expression finally_clause)38   public TryExp (Expression try_clause, Expression finally_clause)
39   {
40     this.try_clause = try_clause;
41     this.finally_clause = finally_clause;
42   }
43 
mustCompile()44   protected boolean mustCompile () { return false; }
45 
46   @Override
apply(CallContext ctx)47   public void apply (CallContext ctx) throws Throwable
48   {
49     try
50       {
51 	try_clause.apply(ctx);
52         ctx.runUntilDone();
53       }
54     catch (Throwable ex)
55       {
56         for (CatchClause clause = catch_clauses; clause != null;
57              clause = clause.next)
58           {
59             Declaration decl = clause.firstDecl();
60             ClassType typeVal = (ClassType) decl.getTypeExp().eval(ctx);
61             if (typeVal.isInstance(ex))
62               {
63                 ctx.setupApply(clause, ex);
64                 ctx.runUntilDone();
65                 return;
66               }
67           }
68         throw ex;
69       }
70     finally
71       {
72         if (finally_clause != null)
73           finally_clause.eval(ctx);
74       }
75   }
76 
compile(Compilation comp, Target target)77   public void compile (Compilation comp, Target target)
78   {
79     CodeAttr code = comp.getCode();
80     boolean has_finally = finally_clause != null;
81     Target ttarg;
82     if (target instanceof StackTarget
83         || target instanceof ConsumerTarget || target instanceof IgnoreTarget
84         || (target instanceof ConditionalTarget && finally_clause == null))
85       ttarg = target;
86     else
87       ttarg = Target.pushValue(target.getType());
88     code.emitTryStart(has_finally,
89                       ttarg instanceof StackTarget ? ttarg.getType() : null);
90     try_clause.compileWithPosition(comp, ttarg);
91     CatchClause catch_clause = catch_clauses;
92     for (; catch_clause != null;  catch_clause = catch_clause.getNext())
93       {
94         Variable callContextSave = comp.callContextVar;
95 	catch_clause.compile(comp, ttarg);
96         comp.callContextVar = callContextSave;
97       }
98 
99     if (finally_clause != null)
100       {
101 	code.emitFinallyStart();
102 	finally_clause.compileWithPosition(comp, Target.Ignore);
103 	code.emitFinallyEnd();
104       }
105     code.emitTryCatchEnd();
106     if (ttarg != target)
107       target.compileFromStack(comp, target.getType());
108   }
109 
visit(ExpVisitor<R,D> visitor, D d)110   protected <R,D> R visit (ExpVisitor<R,D> visitor, D d)
111   {
112     return visitor.visitTryExp(this, d);
113   }
114 
visitChildren(ExpVisitor<R,D> visitor, D d)115   protected <R,D> void visitChildren (ExpVisitor<R,D> visitor, D d)
116   {
117     try_clause = visitor.visitAndUpdate(try_clause, d);
118     CatchClause catch_clause = catch_clauses;
119     while (visitor.exitValue == null && catch_clause != null)
120       {
121 	visitor.visit(catch_clause, d); // FIXME update?
122 	catch_clause = catch_clause.getNext();
123       }
124 
125     if (visitor.exitValue == null && finally_clause != null)
126       finally_clause = visitor.visitAndUpdate(finally_clause, d);
127   }
128 
calculateType()129     protected gnu.bytecode.Type calculateType() {
130         Type t = try_clause.getType();
131         for (CatchClause clause = catch_clauses;
132              clause != null; clause = clause.getNext())  {
133             t = Language.unionType(t, clause.getType());
134         }
135         return t;
136     }
137 
print(OutPort ps)138   public void print (OutPort ps)
139   {
140     ps.startLogicalBlock("(Try", ")", 2);
141     ps.writeSpaceFill();
142     try_clause.print(ps);
143     CatchClause catch_clause = catch_clauses;
144     for (; catch_clause != null;  catch_clause = catch_clause.getNext())
145       {
146 	catch_clause.print(ps);
147       }
148     if (finally_clause != null)
149       {
150 	ps.writeSpaceLinear();
151 	ps.print(" finally: ");
152 	finally_clause.print(ps);
153       }
154     ps.endLogicalBlock(")");
155   }
156 }
157