001: /*
002: * $Id: Statement.java,v 1.47 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.core.Any;
014: import anvil.core.Array;
015: import anvil.codec.Source;
016: import anvil.codec.Target;
017: import anvil.codec.ExceptionHandler;
018: import anvil.parser.Tag;
019: import anvil.ErrorListener;
020: import anvil.script.compiler.ByteCompiler;
021: import anvil.script.Context;
022: import anvil.script.expression.Expression;
023: import anvil.script.parser.TemplateParser;
024: import anvil.script.Grammar;
025: import anvil.script.Scope;
026: import anvil.script.Type;
027: import anvil.java.util.Holder;
028: import java.io.IOException;
029: import java.util.Hashtable;
030:
031: /**
032: * class Statement
033: *
034: * @author: Jani Lehtimäki
035: */
036: public abstract class Statement {
037:
038: static final public Statement EMPTY = new Statement(null, null) {
039: };
040:
041: static final public String DEFAULT_NAMESPACE = "anvil";
042:
043: public static final int CONTENT_PRESERVE = 0;
044: public static final int CONTENT_COMPRESS = 1;
045: public static final int CONTENT_PACK = 2;
046: public static final int CONTENT_SILENT = 3;
047:
048: public static final String[] CONTENT_PROCESSING = { "preserve",
049: "compress", "pack", "silent" };
050:
051: static final public int ST_INVALID = -1;
052: static final public int ST_NONE = 0;
053:
054: static final public int ST_BREAK = 1;
055: static final public int ST_CALL = 2;
056: static final public int ST_CASE = 3;
057: static final public int ST_CATCH = 4;
058: static final public int ST_CDATA = 5;
059: static final public int ST_CLASS = 6;
060: static final public int ST_COMPRESS = 7;
061: static final public int ST_CONST = 8;
062: static final public int ST_CONTINUE = 9;
063: static final public int ST_DEFAULT = 10;
064: static final public int ST_DO = 11;
065: static final public int ST_DOCUMENT = 12;
066: static final public int ST_ELSE = 13;
067: static final public int ST_ELSEIF = 14;
068: static final public int ST_ENDCASE = 15;
069: static final public int ST_ENDDEFAULT = 16;
070: static final public int ST_ENDEVAL = 17;
071: static final public int ST_ENDFOR = 18;
072: static final public int ST_ENDFOREACH = 19;
073: static final public int ST_ENDFUNCTION = 20;
074: static final public int ST_ENDIF = 21;
075: static final public int ST_ENDMODULE = 22;
076: static final public int ST_ENDREPLACE = 23;
077: static final public int ST_ENDSWITCH = 24;
078: static final public int ST_ENDWHILE = 25;
079: static final public int ST_EVAL = 27;
080: static final public int ST_FINALLY = 28;
081: static final public int ST_FOR = 29;
082: static final public int ST_FOREACH = 30;
083: static final public int ST_FUNCTION = 31;
084: static final public int ST_IF = 32;
085: static final public int ST_IMPORT = 33;
086: static final public int ST_INTERFACE = 34;
087: static final public int ST_INVOKE = 35;
088: static final public int ST_MODULE = 36;
089: static final public int ST_PRESERVE = 37;
090: static final public int ST_PRINT = 38;
091: static final public int ST_REPLACE = 39;
092: static final public int ST_RETURN = 40;
093: static final public int ST_SILENT = 41;
094: static final public int ST_SWITCH = 42;
095: static final public int ST_TAG = 43;
096: static final public int ST_THROW = 44;
097: static final public int ST_TRY = 45;
098: static final public int ST_VAR = 46;
099: static final public int ST_WHILE = 47;
100: static final public int ST_ASSERT = 49;
101: static final public int ST_EXIT = 50;
102: static final public int ST_BLOCK = 51;
103: static final public int ST_CUSTOM_TAG = 52;
104: static final public int ST_SYNCHRONIZED = 53;
105: static final public int ST_YIELD = 54;
106: static final public int ST_ENDCLASS = 55;
107: static final public int ST_NAMESPACE = 56;
108: static final public int ST_ENDNAMESPACE = 57;
109: static final public int ST_IMPLICIT_BLOCK = 58;
110: static final public int ST_PACK = 59;
111:
112: static final private Hashtable _tags = new Hashtable();
113:
114: static {
115: _tags.put("module", new Integer(ST_MODULE));
116: _tags.put("/module", new Integer(ST_ENDMODULE));
117:
118: _tags.put("import", new Integer(ST_IMPORT));
119:
120: _tags.put("var", new Integer(ST_VAR));
121: _tags.put("const", new Integer(ST_CONST));
122:
123: _tags.put("function", new Integer(ST_FUNCTION));
124: _tags.put("/function", new Integer(ST_ENDFUNCTION));
125:
126: _tags.put("print", new Integer(ST_PRINT));
127: _tags.put("replace", new Integer(ST_REPLACE));
128: _tags.put("/replace", new Integer(ST_ENDREPLACE));
129:
130: _tags.put("if", new Integer(ST_IF));
131: _tags.put("else", new Integer(ST_ELSE));
132: _tags.put("elseif", new Integer(ST_ELSEIF));
133: _tags.put("/if", new Integer(ST_ENDIF));
134:
135: _tags.put("while", new Integer(ST_WHILE));
136: _tags.put("/while", new Integer(ST_ENDWHILE));
137:
138: _tags.put("return", new Integer(ST_RETURN));
139: _tags.put("break", new Integer(ST_BREAK));
140: _tags.put("continue", new Integer(ST_CONTINUE));
141:
142: _tags.put("switch", new Integer(ST_SWITCH));
143: _tags.put("case", new Integer(ST_CASE));
144: _tags.put("/case", new Integer(ST_ENDCASE));
145: _tags.put("default", new Integer(ST_DEFAULT));
146: _tags.put("/default", new Integer(ST_ENDDEFAULT));
147: _tags.put("/switch", new Integer(ST_ENDSWITCH));
148:
149: _tags.put("foreach", new Integer(ST_FOREACH));
150: _tags.put("/foreach", new Integer(ST_ENDFOREACH));
151:
152: _tags.put("for", new Integer(ST_FOR));
153: _tags.put("/for", new Integer(ST_ENDFOR));
154:
155: _tags.put("eval", new Integer(ST_EVAL));
156: _tags.put("/eval", new Integer(ST_ENDEVAL));
157:
158: _tags.put("preserve", new Integer(ST_PRESERVE));
159: _tags.put("compress", new Integer(ST_COMPRESS));
160: _tags.put("silent", new Integer(ST_SILENT));
161:
162: _tags.put("call", new Integer(ST_CALL));
163: _tags.put("invoke", new Integer(ST_INVOKE));
164:
165: _tags.put("class", new Integer(ST_CLASS));
166: _tags.put("/class", new Integer(ST_ENDCLASS));
167:
168: _tags.put("namespace", new Integer(ST_NAMESPACE));
169: _tags.put("/namespace", new Integer(ST_ENDNAMESPACE));
170:
171: }
172:
173: public static int getTagId(Tag tag) {
174: Integer id = (Integer) _tags.get(tag.getName().toLowerCase());
175: if (id != null) {
176: return id.intValue();
177: } else {
178: return ST_INVALID;
179: }
180: }
181:
182: private Location _location;
183: private Statement _parent;
184:
185: public Statement(Statement parent) {
186: _parent = parent;
187: }
188:
189: public Statement(Location location) {
190: _location = location;
191: }
192:
193: public Statement(Statement parent, Location location) {
194: _parent = parent;
195: _location = location;
196: }
197:
198: public int typeOf() {
199: return ST_NONE;
200: }
201:
202: public String name() {
203: return "statement";
204: }
205:
206: public void setLocation(Location location) {
207: _location = location;
208: }
209:
210: public Location getLocation() {
211: return _location;
212: }
213:
214: public Statement getParentStatement() {
215: return _parent;
216: }
217:
218: public void setParentStatement(Statement parent) {
219: _parent = parent;
220: }
221:
222: public boolean hasEnd() {
223: return false;
224: }
225:
226: public boolean isStaticRegion() {
227: return getParentStatement().isStaticRegion();
228: }
229:
230: public boolean hasStaticContent() {
231: return false;
232: }
233:
234: public String getStaticContent() {
235: return "";
236: }
237:
238: public BlockStatement getBlockStatement() {
239: Statement stmt = getChildStatement();
240: if (stmt instanceof BlockStatement) {
241: return (BlockStatement) stmt;
242: } else {
243: throw new RuntimeException("Child '" + stmt
244: + "' is not instance of BlockStatement");
245: }
246: }
247:
248: public void addChild(Statement statement) {
249: getBlockStatement().add(statement);
250: }
251:
252: public Statement getChildStatement() {
253: return null;
254: }
255:
256: public void setChildStatement(Statement child) {
257: //throw new RuntimeException("Statement.setChildStatement called at "+this.getClass());
258: }
259:
260: public void parse(TemplateParser parser, Tag tag) {
261: }
262:
263: public void importExternals(ErrorListener context) {
264: }
265:
266: public void check(ErrorListener context) {
267: }
268:
269: public Jumps eliminate(ErrorListener context) {
270: return new Jumps();
271: }
272:
273: private void doAddCharacters(TemplateParser parser, String cdata) {
274: FunctionStatement function = getFunctionStatement();
275: if (function != null) {
276: switch (function.getContentState()) {
277: case CONTENT_SILENT:
278: return;
279: case CONTENT_PRESERVE:
280: break;
281: case CONTENT_COMPRESS:
282: cdata = compress(cdata);
283: break;
284: case CONTENT_PACK:
285: cdata = pack(cdata);
286: break;
287: }
288: }
289: if (cdata.length() == 0) {
290: return;
291: }
292: addChild(new CharacterDataStatement(this , parser.getLocation(),
293: cdata));
294: }
295:
296: public void onCharacters(TemplateParser parser, String cdata) {
297: if ((cdata.length() >= 11) && cdata.startsWith("<!--/*")
298: && cdata.endsWith("*/-->")) {
299: return;
300: }
301:
302: if (cdata.indexOf("${") >= 0) {
303: StringBuffer buffer = new StringBuffer();
304: int n = cdata.length();
305: for (int i = 0; i < n; i++) {
306: char ch = cdata.charAt(i);
307:
308: if ((ch == '\\') && (i + 1 < n)) {
309: buffer.append(cdata.charAt(++i));
310:
311: } else if ((ch == '$') && (i + 2 < n)) {
312: ch = cdata.charAt(++i);
313: if (ch != '{') {
314: buffer.append('$');
315: buffer.append(ch);
316: continue;
317: }
318:
319: if (buffer.length() > 0) {
320: doAddCharacters(parser, buffer.toString());
321: }
322: buffer.setLength(0);
323:
324: boolean singleQuote = false;
325: boolean doubleQuote = false;
326: int nesting = 1;
327:
328: while (i + 1 < n && nesting > 0) {
329: ch = cdata.charAt(++i);
330: switch (ch) {
331: case '{':
332: if (!singleQuote || !doubleQuote) {
333: nesting++;
334: }
335: buffer.append(ch);
336: break;
337: case '}':
338: if (!singleQuote || !doubleQuote) {
339: nesting--;
340: }
341: if (nesting > 0) {
342: buffer.append(ch);
343: }
344: break;
345: case '\\':
346: if (i + 1 < n) {
347: char nextch = cdata.charAt(++i);
348: if (nextch == '}' || nextch == '{') {
349: buffer.append(nextch);
350: } else {
351: buffer.append(ch);
352: buffer.append(nextch);
353: }
354: }
355: break;
356: case '\'':
357: if (!doubleQuote) {
358: singleQuote = !singleQuote;
359: }
360: buffer.append(ch);
361: break;
362: case '"':
363: if (!singleQuote) {
364: doubleQuote = !doubleQuote;
365: }
366: buffer.append(ch);
367: break;
368:
369: default:
370: buffer.append(ch);
371: }
372: }
373:
374: Expression expr = Grammar.parseExpression(buffer
375: .toString(), getLocation(), parser);
376: if (expr.isConstant()) {
377: addChild(new CharacterDataStatement(this ,
378: parser.getLocation(), expr.eval()
379: .toString()));
380: } else {
381: addChild(new PrintStatement(this , parser
382: .getLocation(), expr));
383: }
384: buffer.setLength(0);
385:
386: } else {
387: buffer.append(ch);
388: }
389:
390: }
391:
392: if (buffer.length() > 0) {
393: doAddCharacters(parser, buffer.toString());
394: }
395:
396: } else {
397: doAddCharacters(parser, cdata);
398: }
399: }
400:
401: public anvil.script.statements.taglib.Tag getTag(String ns,
402: String name) {
403: Statement parent = getParentStatement();
404: if (parent != null) {
405: return parent.getTag(ns, name);
406: } else {
407: return null;
408: }
409: }
410:
411: public boolean onTag(TemplateParser parser, int type, Tag tag) {
412: Statement statement = null;
413: boolean addblock = false;
414: BlockStatement block = getBlockStatement();
415:
416: switch (type) {
417: case ST_TAG: {
418: String ns = tag.getNamespace();
419: String name = tag.getName();
420: anvil.script.statements.taglib.Tag tagdef = getTag(ns, name);
421: if (tagdef != null) {
422: statement = new CustomTagStatement(block, parser
423: .getLocation(), tagdef, tag);
424: addblock = statement.hasEnd();
425: break;
426: }
427: FunctionStatement function = getFunctionStatement();
428: if (function == null
429: || function.getContentState() != Statement.CONTENT_SILENT) {
430: onCharacters(parser, tag.toString());
431: }
432: return true;
433: }
434:
435: case ST_EVAL:
436: statement = new EvalStatement(block, parser.getLocation());
437: addblock = true;
438: break;
439:
440: case ST_PRINT:
441: statement = new PrintStatement(block, parser.getLocation());
442: break;
443:
444: case ST_CALL:
445: statement = new CallStatement(block, parser.getLocation());
446: break;
447:
448: case ST_INVOKE:
449: statement = new InvokeStatement(block, parser.getLocation());
450: break;
451:
452: case ST_RETURN:
453: statement = new ReturnStatement(block, parser.getLocation());
454: break;
455:
456: case ST_PACK:
457: statement = new PackStatement(block, parser.getLocation());
458: break;
459:
460: case ST_PRESERVE:
461: statement = new PreserveStatement(block, parser
462: .getLocation());
463: break;
464:
465: case ST_COMPRESS:
466: statement = new CompressStatement(block, parser
467: .getLocation());
468: break;
469:
470: case ST_SILENT:
471: statement = new SilentStatement(block, parser.getLocation());
472: break;
473:
474: case ST_IF:
475: statement = new IfStatement(block, parser.getLocation());
476: addblock = true;
477: break;
478:
479: case ST_REPLACE:
480: statement = new ReplaceStatement(block, parser
481: .getLocation());
482: break;
483:
484: case ST_WHILE:
485: statement = new WhileStatement(block, parser.getLocation());
486: addblock = true;
487: break;
488:
489: case ST_FOREACH:
490: statement = new ForeachStatement(block, parser
491: .getLocation());
492: addblock = true;
493: break;
494:
495: case ST_FOR:
496: statement = new ForStatement(block, parser.getLocation());
497: addblock = true;
498: break;
499:
500: case ST_SWITCH:
501: statement = new SwitchStatement(block, parser.getLocation());
502: break;
503:
504: case ST_BREAK:
505: if (!allowBreak()) {
506: parser
507: .error(getLocation(),
508: "Useless break, no valid enclosing statements open");
509: } else {
510: statement = new BreakStatement(block, parser
511: .getLocation());
512: }
513: break;
514:
515: case ST_CONTINUE:
516: if (!allowContinue()) {
517: parser
518: .error(getLocation(),
519: "Useless continue, no valid enclosing statements open");
520: } else {
521: statement = new ContinueStatement(block, parser
522: .getLocation());
523: }
524: break;
525: }
526:
527: if (statement == null) {
528: return false;
529: }
530:
531: statement.parse(parser, tag);
532:
533: addChild(statement);
534: if (statement.hasEnd()) {
535: parser.push(statement);
536: if (addblock) {
537: statement.setChildStatement(new ImplicitBlockStatement(
538: statement, statement.getLocation()));
539: }
540: }
541:
542: return true;
543: }
544:
545: public boolean onProcessingInstruction(TemplateParser parser,
546: String data) {
547: onCharacters(parser, "<?" + data + "?>");
548: return true;
549: }
550:
551: public CatchStatement getCatchStatement() {
552: Statement stmt = this ;
553: while (stmt != null) {
554: if (stmt.typeOf() == ST_CATCH) {
555: return (CatchStatement) stmt;
556: }
557: stmt = stmt.getParentStatement();
558: }
559: return null;
560: }
561:
562: public ModuleStatement getModuleStatement() {
563: Statement stmt = this ;
564: while (stmt != null) {
565: if (stmt.typeOf() == ST_MODULE) {
566: return (ModuleStatement) stmt;
567: }
568: stmt = stmt.getParentStatement();
569: }
570: return null;
571: }
572:
573: public ClassStatement getClassStatement() {
574: Statement stmt = this ;
575: while (stmt != null) {
576: if (stmt.typeOf() == ST_CLASS) {
577: return (ClassStatement) stmt;
578: }
579: stmt = stmt.getParentStatement();
580: }
581: return null;
582: }
583:
584: public InterfaceStatement getInterfaceStatement() {
585: Statement stmt = this ;
586: while (stmt != null) {
587: if (stmt.typeOf() == ST_INTERFACE) {
588: return (InterfaceStatement) stmt;
589: }
590: stmt = stmt.getParentStatement();
591: }
592: return null;
593: }
594:
595: public FunctionStatement getFunctionStatement() {
596: Statement stmt = this ;
597: while (stmt != null) {
598: if (stmt.typeOf() == ST_FUNCTION) {
599: return (FunctionStatement) stmt;
600: }
601: stmt = stmt.getParentStatement();
602: }
603: return null;
604: }
605:
606: public DefinitionStatement getDefinitionStatement() {
607: Statement stmt = this ;
608: while (stmt != null) {
609: if (stmt instanceof DefinitionStatement) {
610: return (DefinitionStatement) stmt;
611: }
612: stmt = stmt.getParentStatement();
613: }
614: return null;
615: }
616:
617: public DefinitionStatement getScopeStatement() {
618: Statement stmt = this ;
619: while (stmt != null) {
620: if (stmt instanceof DefinitionStatement
621: && stmt.typeOf() != ST_FUNCTION) {
622: return (DefinitionStatement) stmt;
623: }
624: stmt = stmt.getParentStatement();
625: }
626: return null;
627: }
628:
629: public Type lookupAnyDeclaration(String name) {
630: Statement stmt = this ;
631: while (stmt != null) {
632: switch (stmt.typeOf()) {
633: case Statement.ST_MODULE:
634: case Statement.ST_CLASS:
635: case Statement.ST_INTERFACE:
636: case Statement.ST_NAMESPACE:
637: case Statement.ST_FUNCTION: {
638: DefinitionStatement defstmt = (DefinitionStatement) stmt;
639: Type type = defstmt.lookupDeclaration(name);
640: if (type != null) {
641: return type;
642: }
643: }
644: break;
645: }
646: stmt = stmt.getParentStatement();
647: }
648: return null;
649: }
650:
651: public boolean isDeclared(String name) {
652: return (lookupAnyDeclaration(name) != null);
653: }
654:
655: public boolean allowBreak() {
656: Statement stmt = this ;
657: while (stmt != null) {
658: switch (stmt.typeOf()) {
659: case Statement.ST_BLOCK:
660: case Statement.ST_WHILE:
661: case Statement.ST_DO:
662: case Statement.ST_FOREACH:
663: case Statement.ST_FOR:
664: case Statement.ST_SWITCH:
665: return true;
666: case Statement.ST_IF:
667: case Statement.ST_TRY:
668: case Statement.ST_CATCH:
669: case Statement.ST_FINALLY:
670: case Statement.ST_SYNCHRONIZED:
671: case Statement.ST_IMPLICIT_BLOCK:
672: break;
673: default:
674: return false;
675: }
676: stmt = stmt.getParentStatement();
677: }
678: return false;
679: }
680:
681: public boolean allowContinue() {
682: Statement stmt = this ;
683: while (stmt != null) {
684: switch (stmt.typeOf()) {
685: case Statement.ST_BLOCK:
686: case Statement.ST_WHILE:
687: case Statement.ST_DO:
688: case Statement.ST_FOREACH:
689: case Statement.ST_FOR:
690: return true;
691: case Statement.ST_SWITCH:
692: case Statement.ST_IF:
693: case Statement.ST_TRY:
694: case Statement.ST_CATCH:
695: case Statement.ST_FINALLY:
696: case Statement.ST_SYNCHRONIZED:
697: case Statement.ST_IMPLICIT_BLOCK:
698: break;
699: default:
700: return false;
701: }
702: stmt = stmt.getParentStatement();
703: }
704: return false;
705: }
706:
707: public boolean allowYield() {
708: Statement stmt = this ;
709: while (stmt != null) {
710: switch (stmt.typeOf()) {
711: case ST_FUNCTION:
712: return true;
713: case Statement.ST_FINALLY:
714: case Statement.ST_SYNCHRONIZED:
715: return false;
716: case Statement.ST_TRY: {
717: TryStatement trystmt = (TryStatement) stmt;
718: if (trystmt.getFinally() != null) {
719: return false;
720: }
721: }
722: break;
723: default:
724: break;
725: }
726: stmt = stmt.getParentStatement();
727: }
728: return true;
729: }
730:
731: public boolean allowLabel(String label) {
732: Statement stmt = this ;
733: while (stmt != null) {
734: if (stmt instanceof Labeled) {
735: String candidate = ((Labeled) stmt).getLabel();
736: if ((candidate != null) && (label.equals(candidate))) {
737: return true;
738: }
739: }
740: stmt = stmt.getParentStatement();
741: }
742: return false;
743: }
744:
745: public int getLabelDepth(String label) {
746: int depth = 0;
747: Statement stmt = this ;
748: while (stmt != null) {
749: if (stmt instanceof Labeled) {
750: String candidate = ((Labeled) stmt).getLabel();
751: if ((candidate != null) && (label.equals(candidate))) {
752: return depth;
753: }
754: depth++;
755: }
756: stmt = stmt.getParentStatement();
757: }
758: return -1;
759: }
760:
761: public Labeled getLabeled(String label, boolean iscont) {
762: Statement stmt = this ;
763: while (stmt != null) {
764: if (stmt instanceof Labeled) {
765: Labeled labeled = (Labeled) stmt;
766: if (label != null) {
767: String candidate = labeled.getLabel();
768: if ((candidate != null)
769: && (label.equals(candidate))) {
770: if (!iscont || stmt.typeOf() != ST_SWITCH) {
771: return labeled;
772: }
773: }
774: } else {
775: return labeled;
776: }
777: }
778: stmt = stmt.getParentStatement();
779: }
780: return null;
781: }
782:
783: public SwitchStatement getSwitch(String label) {
784: Statement stmt = this ;
785: while (stmt != null) {
786: if (stmt.typeOf() == ST_SWITCH) {
787: SwitchStatement select = (SwitchStatement) stmt;
788: if (label != null) {
789: String candidate = select.getLabel();
790: if ((candidate != null)
791: && (label.equals(candidate))) {
792: return select;
793: }
794: } else {
795: return select;
796: }
797: }
798: stmt = stmt.getParentStatement();
799: }
800: return null;
801: }
802:
803: public void compile(ByteCompiler context) {
804: }
805:
806: public boolean isBlocked() {
807: return false;
808: }
809:
810: public boolean callFinalizer() {
811: return false;
812: }
813:
814: public int getTypeRef(anvil.codec.ConstantPool pool, int type) {
815: return 0;
816: }
817:
818: public static final String compress(String cdata) {
819: if (cdata.charAt(0) == '<') {
820: return cdata;
821: }
822:
823: int n = cdata.length();
824: int i = 0;
825: char ch;
826: char pad = ' ';
827: StringBuffer buffer = new StringBuffer(n);
828:
829: while (i < n) {
830: ch = cdata.charAt(i);
831: if (Character.isWhitespace(ch)) {
832: pad = (ch == '\n') ? '\n' : ' ';
833: while ((++i) < n) {
834: ch = cdata.charAt(i);
835: if (!Character.isWhitespace(ch)) {
836: break;
837: }
838: if (ch == '\n') {
839: pad = '\n';
840: }
841: }
842: buffer.append(pad);
843: } else {
844: buffer.append(ch);
845: i++;
846: }
847: }
848:
849: return buffer.toString();
850: }
851:
852: public static final String pack(String cdata) {
853: if (cdata.charAt(0) == '<') {
854: return cdata;
855: }
856:
857: int length = cdata.length();
858:
859: int end = length;
860:
861: for (; end > 0; end--) {
862: if (!Character.isWhitespace(cdata.charAt(end - 1))) {
863: break;
864: }
865: }
866:
867: int start = 0;
868: for (; start < end; start++) {
869: if (!Character.isWhitespace(cdata.charAt(start))) {
870: break;
871: }
872: }
873:
874: StringBuffer buffer = new StringBuffer(end - start + 1);
875: int i = start;
876: while (i < end) {
877: char ch = cdata.charAt(i);
878: if (Character.isWhitespace(ch)) {
879: char pad = ' ';
880: while (true) {
881: if (ch == '\n') {
882: pad = '\n';
883: }
884: if (i++ >= end) {
885: break;
886: }
887: ch = cdata.charAt(i);
888: if (!Character.isWhitespace(ch)) {
889: break;
890: }
891: }
892: buffer.append(pad);
893: } else {
894: buffer.append(ch);
895: i++;
896: }
897: }
898:
899: return buffer.toString();
900: }
901:
902: public final String parseLabel(TemplateParser parser, Tag tag) {
903: String label = tag.getValue("label");
904: if (label != null) {
905: if (!Grammar.isValidIdentifier(label)) {
906: parser.error(getLocation(), "Label '" + label
907: + "' is not a valid identifier");
908: return null;
909: }
910:
911: if (allowLabel(label)) {
912: parser.error(getLocation(), "Label '" + label
913: + "' is already declared");
914: return null;
915: }
916: }
917: return label;
918: }
919:
920: public int getContentState() {
921: return getParentStatement().getContentState();
922: }
923:
924: }
|