001: /*
002: * $Id: TryStatement.java,v 1.7 2002/09/16 08:05:06 jkl Exp $
003: *
004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
005: *
006: * Use is subject to license terms, as defined in
007: * Anvil Sofware License, Version 1.1. See LICENSE
008: * file, or http://njet.org/license-1.1.txt
009: */
010: package anvil.script.statements;
011:
012: import anvil.Location;
013: import anvil.codec.Code;
014: import anvil.codec.ExceptionHandler;
015: import anvil.parser.Tag;
016: import anvil.ErrorListener;
017: import anvil.script.compiler.ByteCompiler;
018: import anvil.script.Context;
019: import anvil.script.ScriptException;
020: import anvil.script.parser.TemplateParser;
021: import java.io.IOException;
022:
023: /**
024: * class TryStatement
025: *
026: * @author: Jani Lehtimäki
027: */
028: public class TryStatement extends ScopedStatement {
029:
030: protected Statement _statement = EMPTY;
031: protected CatchStatement[] _catch = new CatchStatement[4];
032: protected int _catches = 0;
033: protected FinallyStatement _finally = null;
034: protected ExceptionHandler _handler = null;
035:
036: public TryStatement(Statement parent, Location location) {
037: super (parent, location);
038: }
039:
040: public int typeOf() {
041: return Statement.ST_TRY;
042: }
043:
044: public String name() {
045: return "try";
046: }
047:
048: public Statement getChildStatement() {
049: return _statement;
050: }
051:
052: public void setChildStatement(Statement statement) {
053: _statement = statement;
054: }
055:
056: public FinallyStatement getFinally() {
057: return _finally;
058: }
059:
060: public boolean hasFinally() {
061: return _finally != null;
062: }
063:
064: public void addCatch(CatchStatement stmt) {
065: int n = _catch.length;
066: if (_catches >= n) {
067: CatchStatement[] katch = new CatchStatement[n += 4];
068: System.arraycopy(_catch, 0, katch, 0, n);
069: _catch = katch;
070: }
071: _catch[_catches++] = stmt;
072: }
073:
074: public void setFinally(FinallyStatement stmt) {
075: _finally = stmt;
076: }
077:
078: public boolean onTag(TemplateParser parser, int type, Tag tag) {
079: return true;
080: }
081:
082: public void check(ErrorListener context) {
083: _statement.check(context);
084: boolean seentypeless = false;
085: for (int i = 0; i < _catches; i++) {
086: CatchStatement katch = _catch[i];
087: if (seentypeless) {
088: context
089: .error(katch.getLocation(),
090: "Dead code: preceding non-typed catch renders this catch block inaccessible");
091: }
092: if (katch.isTypeless()) {
093: if (seentypeless) {
094: context
095: .error(katch.getLocation(),
096: "There may be only one non-typed catch statement in catch sequence");
097: }
098: seentypeless = true;
099: }
100: katch.check(context);
101: }
102: if (_finally != null) {
103: _finally.check(context);
104: }
105: }
106:
107: public Jumps eliminate(ErrorListener context) {
108: Jumps jumps = _statement.eliminate(context);
109:
110: for (int i = 0; i < _catches; i++) {
111: Statement katch = _catch[i];
112: boolean blocked = jumps.isBlocked();
113: jumps.setThrow(false).setBlocked(false);
114: Jumps j = katch.eliminate(context);
115: blocked = blocked && j.isBlocked();
116: jumps.merge(j);
117: jumps.setBlocked(blocked);
118: }
119: if (_finally != null) {
120: boolean blocked = jumps.isBlocked();
121: Jumps j = _finally.eliminate(context);
122: blocked = blocked || j.isBlocked();
123: jumps.merge(j);
124: jumps.setBlocked(blocked);
125: }
126: //_isblocked = jumps.isBlocked();
127: return jumps;
128: }
129:
130: public void compile(ByteCompiler context) {
131: boolean has_try = (_catches > 0) || (_finally != null);
132: if (has_try) {
133: Code code = context.getCode();
134:
135: // try
136: ExceptionHandler handler = code
137: .startExceptionHandler(_finally != null);
138: _handler = handler;
139: if (_statement == EMPTY) {
140: code.nop();
141: } else {
142: _statement.compile(context);
143: }
144: handler.endTry();
145: if (!_statement.isBlocked()) {
146: handler.callFinally();
147: handler.jumpOut();
148: }
149:
150: // catch
151: if (_catches > 0) {
152: handler.startCatch(code.getPool().addClass(
153: "anvil/script/ScriptException"));
154: int l_throwable = code.addLocal();
155: int l_data = code.addLocal();
156: code.astore(l_throwable);
157: code.aload(l_throwable);
158: code.invokevirtual(code.getPool().addMethodRef(
159: "anvil/script/ScriptException", "getData",
160: "()Lanvil/core/Any;"));
161: code.astore(l_data);
162: for (int i = 0; i < _catches; i++) {
163: _catch[i].compile(context, handler, l_data);
164: }
165: code.aload(l_throwable);
166: code.athrow();
167: }
168:
169: handler.endProtectedRegion();
170:
171: if (_finally != null) {
172: handler.startCatch(0);
173: int thrown = code.addLocal();
174: code.astore(thrown);
175: handler.callFinally();
176: code.aload(thrown);
177: code.athrow();
178: }
179: handler.endCatches();
180: _handler = null;
181:
182: // finally
183: if (_finally != null) {
184: handler.startFinally();
185: int returnto = code.addLocal();
186: code.astore(returnto);
187: _finally.compile(context);
188: if (!_finally.isBlocked()) {
189: code.ret(returnto);
190: }
191: handler.endFinally();
192: }
193:
194: handler.end();
195:
196: } else {
197: _statement.compile(context);
198: }
199: }
200:
201: public boolean callFinalizer() {
202: if (_handler == null) {
203: return false;
204: }
205: if (_finally != null) {
206: _handler.callFinally();
207: if (_finally.isBlocked()) {
208: return true;
209: }
210: }
211: return false;
212: }
213:
214: }
|