001: /*
002: * $Id: CustomTagStatement.java,v 1.12 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.core.Any;
013: import anvil.core.Array;
014: import anvil.codec.Code;
015: import anvil.codec.ConstantPool;
016: import anvil.codec.Source;
017: import anvil.codec.Target;
018: import anvil.codec.ExceptionHandler;
019: import anvil.Location;
020: import anvil.ErrorListener;
021: import anvil.script.compiler.ByteCompiler;
022: import anvil.script.Context;
023: import anvil.script.Name;
024: import anvil.script.StackFrame;
025: import anvil.script.expression.ArrayNode;
026: import anvil.script.expression.Node;
027: import anvil.script.expression.ConstantNode;
028: import anvil.script.expression.Expression;
029: import anvil.script.expression.ExpressionList;
030: import anvil.script.expression.LinkNode;
031: import anvil.script.expression.MappingNode;
032: import anvil.script.expression.Expression;
033: import anvil.script.expression.InvokeNode;
034: import anvil.script.parser.TemplateParser;
035: import anvil.script.parser.ExpressionParser;
036: import anvil.script.Grammar;
037: import anvil.script.statements.taglib.TagLibrary;
038: import anvil.script.statements.taglib.Attribute;
039: import anvil.script.statements.taglib.Tag;
040: import java.io.IOException;
041: import java.util.Enumeration;
042: import java.util.ArrayList;
043: import java.util.Iterator;
044:
045: /**ö
046: * class CustomTagStatement
047: *
048: * @author: Jani Lehtimäki
049: */
050: public class CustomTagStatement extends Statement {
051:
052: private String _namespace;
053: private String _name;
054: private Tag _tagdef = null;
055: private anvil.parser.Tag _tag = null;
056: private boolean _hasEnd = false;
057: private Statement _statement = null;
058: private Expression _init = null;
059: private Expression _start = null;
060: private Expression _end = null;
061: private Expression _release = null;
062: private ExceptionHandler _handler = null;
063: private int _framelocal = 0;
064:
065: public CustomTagStatement(Statement parent, Location location,
066: Tag tagdef, anvil.parser.Tag tag) {
067: super (parent, location);
068: _namespace = tagdef.getLibrary().getNamespace();
069: _name = tag.getName();
070: _tagdef = tagdef;
071: _tag = tag;
072: _hasEnd = tagdef.hasContent() && !tag.hasEndSlash();
073: }
074:
075: public int typeOf() {
076: return Statement.ST_CUSTOM_TAG;
077: }
078:
079: public String name() {
080: return _name;
081: }
082:
083: public void parse(TemplateParser parser, anvil.parser.Tag tag) {
084: ArrayList nodes = new ArrayList();
085: Enumeration e = _tagdef.getAttributes();
086: while (e.hasMoreElements()) {
087: Attribute attr = (Attribute) e.nextElement();
088: String name = attr.getName();
089: String value = tag.getValue(attr.getName());
090: if (value == null) {
091: if (attr.isRequired()) {
092: parser
093: .error(parser.getLocation(),
094: "Required attribute '" + name
095: + "' missing");
096: } else {
097: value = attr.getDefault();
098: }
099: }
100: if (value != null) {
101: Node node = ConstantNode.UNDEFINED;
102: switch (attr.getType()) {
103: case Attribute.TYPE_STRING:
104: node = new ConstantNode(Any.create(value));
105: break;
106:
107: case Attribute.TYPE_DOUBLE:
108: try {
109: node = new ConstantNode(Any.create(Double
110: .parseDouble(value)));
111: } catch (NumberFormatException nfe) {
112: parser
113: .error(
114: parser.getLocation(),
115: "Value of attribute '"
116: + name
117: + "' is not a floating point number");
118: }
119: break;
120:
121: case Attribute.TYPE_INT:
122: try {
123: node = new ConstantNode(Any
124: .create(anvil.util.Conversions
125: .parseNumberUnsafe(value)));
126: } catch (NumberFormatException nfe) {
127: parser.error(parser.getLocation(),
128: "Value of attribute '" + name
129: + "' is not an integer");
130: }
131: break;
132:
133: case Attribute.TYPE_BOOLEAN:
134: node = new ConstantNode(Any.create(Any.IS_BOOLEAN,
135: value));
136: break;
137:
138: case Attribute.TYPE_EXPR:
139: value = value.trim();
140: if (value.length() > 0) {
141: ExpressionParser p = new ExpressionParser(
142: parser, parser.getLocation(), value);
143: node = p.parseExpression(p.TYPE_VALUE)
144: .getChild();
145: } else {
146: node = ConstantNode.UNDEFINED;
147: }
148: break;
149: }
150: nodes
151: .add(new MappingNode(new ConstantNode(name),
152: node));
153: }
154: }
155: if (_tagdef.allowAnyAttributes()) {
156: Iterator iter = _tag.getAttributes();
157: while (iter.hasNext()) {
158: anvil.parser.Attribute attr = (anvil.parser.Attribute) iter
159: .next();
160: String name = attr.getName();
161: if (!_tagdef.hasAttribute(name)) {
162: nodes.add(new MappingNode(new ConstantNode(name),
163: new ConstantNode(attr.getValue())));
164: }
165: }
166: }
167:
168: int n = nodes.size();
169: ExpressionList childs = new ExpressionList(n);
170: for (int i = 0; i < n; i++) {
171: childs.setChild(i, (Node) nodes.get(i));
172: }
173:
174: Location location = getLocation();
175:
176: _init = buildExpr(location, _tagdef.getInitHandler(), null,
177: new ExpressionList(new ParentNode(), new ConstantNode(
178: _name), new ArrayNode(childs)));
179:
180: _start = buildExpr(location, _tagdef.getStartHandler(), _tagdef
181: .getStartMethod(), ARGS);
182:
183: _end = buildExpr(location, _tagdef.getEndHandler(), _tagdef
184: .getEndMethod(), ARGS);
185:
186: _release = buildExpr(location, _tagdef.getReleaseHandler(),
187: _tagdef.getReleaseMethod(), ARGS);
188: }
189:
190: public boolean onTag(TemplateParser parser, int type,
191: anvil.parser.Tag tag) {
192: switch (type) {
193: case ST_TAG:
194: if (tag.isEndTagOf(_tag)) {
195: parser.pop();
196: break;
197: }
198:
199: default:
200: return super .onTag(parser, type, tag);
201: }
202:
203: return true;
204: }
205:
206: private Expression buildExpr(Location location, String handler,
207: String method, ExpressionList args) {
208: if (handler != null) {
209: handler = handler.trim();
210: return new Expression(new LinkNode(this , location,
211: new Name().add(_namespace).add(handler), args,
212: LinkNode.GET), location);
213:
214: } else if (method != null) {
215: return new Expression(new InvokeNode(FRAME, method,
216: EMPTY_ARGS), location);
217:
218: } else {
219: return null;
220: }
221: }
222:
223: public boolean hasEnd() {
224: return _hasEnd;
225: }
226:
227: public Statement getChildStatement() {
228: return _statement;
229: }
230:
231: public void setChildStatement(Statement statement) {
232: _statement = statement;
233: }
234:
235: public void check(ErrorListener context) {
236: if (_init != null) {
237: _init.check(context);
238: }
239: if (_start != null) {
240: _start.check(context);
241: }
242: if (_end != null) {
243: _end.check(context);
244: }
245: if (_release != null) {
246: _release.check(context);
247: }
248: if (_statement != null) {
249: _statement.check(context);
250: }
251: }
252:
253: public Jumps eliminate(ErrorListener context) {
254: if (_statement != null) {
255: Jumps jumps = _statement.eliminate(context);
256: jumps.setBlocked(false);
257: return jumps.shift();
258: } else {
259: return new Jumps();
260: }
261: }
262:
263: public void compile(ByteCompiler context) {
264: Code code = context.getCode();
265: ConstantPool pool = code.getPool();
266: boolean needloop = (_start != null) || (_end != null)
267: || (_release != null) || (_statement != null);
268:
269: if (needloop) {
270: if (_init != null) {
271: _init.compile(context, Node.GET);
272: } else {
273: code.getstatic(pool.addFieldRef(context.TYPE_ANY,
274: "UNDEFINED", "Lanvil/core/Any;"));
275: }
276: code.dup();
277:
278: int contextframe = pool.addMethodRef(context.TYPE_CONTEXT,
279: "frame", "()Lanvil/script/StackFrame;");
280: code.aload_first();
281: code.invokevirtual(contextframe);
282: code.swap();
283: code.invokevirtual(pool.addMethodRef(
284: "anvil/script/StackFrame", "push",
285: "(Lanvil/core/Any;)V"));
286:
287: _framelocal = code.addLocal();
288: code.astore(_framelocal);
289:
290: ExceptionHandler handler = code.startExceptionHandler(true);
291: _handler = handler;
292: Target tostart = code.getTarget();
293: if (_start != null) {
294: _start.compile(context, Node.GET_BOOLEAN);
295: Source istrue = code.if_ne();
296: handler.callFinally();
297: handler.jumpOut();
298: istrue.bind();
299: }
300: if (_statement != null) {
301: _statement.compile(context);
302: }
303: if (_end != null) {
304: _end.compile(context, Node.GET_BOOLEAN);
305: code.if_ne(tostart);
306: }
307: handler.endTry();
308: if (_statement == null || !_statement.isBlocked()) {
309: handler.callFinally();
310: handler.jumpOut();
311: }
312: handler.endProtectedRegion();
313:
314: handler.startCatch(0);
315: int thrown = code.addLocal();
316: code.astore(thrown);
317: handler.callFinally();
318: code.aload(thrown);
319: code.athrow();
320: handler.endCatches();
321: _handler = null;
322:
323: // finally
324: handler.startFinally();
325: int returnto = code.addLocal();
326: code.astore(returnto);
327: code.aload_first();
328: code.invokevirtual(contextframe);
329: code.invokevirtual(pool.addMethodRef(
330: "anvil/script/StackFrame", "pop",
331: "()Lanvil/core/Any;"));
332: code.pop();
333: if (_release != null) {
334: _release.compile(context, Node.GET);
335: code.pop();
336: }
337: code.ret(returnto);
338: handler.endFinally();
339: handler.end();
340:
341: code.endLocal(_framelocal);
342:
343: } else {
344: if (_init != null) {
345: _init.compile(context, Node.GET);
346: code.pop();
347: }
348: }
349: }
350:
351: public boolean callFinalizer() {
352: _handler.callFinally();
353: return false;
354: }
355:
356: private Node FRAME = new FrameNode();
357: private ExpressionList ARGS = new ExpressionList(FRAME);
358: private static final ExpressionList EMPTY_ARGS = new ExpressionList(
359: 0);
360:
361: private static class ParentNode extends Node {
362:
363: public void compile(ByteCompiler context, int operation) {
364: Code code = context.getCode();
365: ConstantPool pool = code.getPool();
366: code.aload_first();
367: code.invokevirtual(pool.addMethodRef(context.TYPE_CONTEXT,
368: "frame", "()Lanvil/script/StackFrame;"));
369: code.invokevirtual(pool.addMethodRef(
370: "anvil/script/StackFrame", "peek",
371: "()Lanvil/core/Any;"));
372: }
373:
374: }
375:
376: private class FrameNode extends Node {
377:
378: public void compile(ByteCompiler context, int operation) {
379: Code code = context.getCode();
380: ConstantPool pool = code.getPool();
381: code.aload(_framelocal);
382: }
383:
384: }
385:
386: }
|