View Javadoc
1   package net.sourceforge.jenesis4java.impl;
2   
3   /*
4    * #%L
5    * Jenesis 4 Java Code Generator
6    * %%
7    * Copyright (C) 2000 - 2015 jenesis4java
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  /**
26   * Copyright (C) 2008, 2010 Richard van Nieuwenhoven - ritchie [at] gmx [dot] at
27   * Copyright (C) 2000, 2001 Paul Cody Johnston - pcj@inxar.org <br>
28   * This file is part of Jenesis4java. Jenesis4java is free software: you can
29   * redistribute it and/or modify it under the terms of the GNU Lesser General
30   * Public License as published by the Free Software Foundation, either version 3
31   * of the License, or (at your option) any later version.<br>
32   * Jenesis4java is distributed in the hope that it will be useful, but WITHOUT
33   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
35   * details.<br>
36   * You should have received a copy of the GNU Lesser General Public License
37   * along with Jenesis4java. If not, see <http://www.gnu.org/licenses/>.
38   */
39  import java.util.ArrayList;
40  import java.util.List;
41  
42  import net.sourceforge.jenesis4java.CodeWriter;
43  import net.sourceforge.jenesis4java.Comment;
44  import net.sourceforge.jenesis4java.DocumentationComment;
45  import net.sourceforge.jenesis4java.ReplacingVisitor;
46  import net.sourceforge.jenesis4java.impl.util.ListTypeSelector;
47  
48  /**
49   * Standard {@code Comment} implementations.
50   */
51  abstract class MComment extends MVM.MCodeable implements Comment {
52  
53      /**
54       * DOCUMENTATION COMMENT
55       */
56      static class MDocumentationComment extends MComment implements DocumentationComment {
57  
58          String tagAuthor;
59  
60          String tagDate;
61  
62          String tagDeprecated;
63  
64          String tagException;
65  
66          String tagReturn;
67  
68          String tagSerial;
69  
70          String tagSerialData;
71  
72          String tagSerialField;
73  
74          String tagSince;
75  
76          String tagThrows;
77  
78          String tagVersion;
79  
80          List<String> vtagParameter;
81  
82          List<String> vtagSee;
83  
84          public MDocumentationComment(MVM vm, String text) {
85              super(vm, Comment.DOCUMENTATION, text);
86              vtagParameter = new ArrayList<>();
87              vtagSee = new ArrayList<>();
88          }
89  
90          @Override
91          public MDocumentationComment addParam(String s) {
92              vtagParameter.add(s);
93              return this;
94          }
95  
96          @Override
97          public MDocumentationComment addSee(String s) {
98              vtagSee.add(s);
99              return this;
100         }
101 
102         @Override
103         public String getAuthor() {
104             return tagAuthor;
105         }
106 
107         @Override
108         public String getDate() {
109             return tagDate;
110         }
111 
112         @Override
113         public String getDeprecated() {
114             return tagDeprecated;
115         }
116 
117         @Override
118         public String getException() {
119             return tagException;
120         }
121 
122         @Override
123         public List<String> getParams() {
124             return ListTypeSelector.select(vtagParameter);
125         }
126 
127         @Override
128         public String getReturn() {
129             return tagReturn;
130         }
131 
132         @Override
133         public List<String> getSees() {
134             return ListTypeSelector.select(vtagSee);
135         }
136 
137         @Override
138         public String getSerial() {
139             return tagSerial;
140         }
141 
142         @Override
143         public String getSerialData() {
144             return tagSerialData;
145         }
146 
147         @Override
148         public String getSerialField() {
149             return tagSerialField;
150         }
151 
152         @Override
153         public String getSince() {
154             return tagSince;
155         }
156 
157         @Override
158         public String getThrows() {
159             return tagThrows;
160         }
161 
162         @Override
163         public String getVersion() {
164             return tagVersion;
165         }
166 
167         @Override
168         public MDocumentationComment setAuthor(String s) {
169             tagAuthor = s;
170             return this;
171         }
172 
173         @Override
174         public MDocumentationComment setDate(String s) {
175             tagDate = s;
176             return this;
177         }
178 
179         @Override
180         public MDocumentationComment setDeprecated(String s) {
181             tagDeprecated = s;
182             return this;
183         }
184 
185         @Override
186         public MDocumentationComment setException(String s) {
187             tagException = s;
188             return this;
189         }
190 
191         @Override
192         public MDocumentationComment setReturn(String s) {
193             tagReturn = s;
194             return this;
195         }
196 
197         @Override
198         public MDocumentationComment setSerial(String s) {
199             tagSerial = s;
200             return this;
201         }
202 
203         @Override
204         public MDocumentationComment setSerialData(String s) {
205             tagSerialData = s;
206             return this;
207         }
208 
209         @Override
210         public MDocumentationComment setSerialField(String s) {
211             tagSerialField = s;
212             return this;
213         }
214 
215         @Override
216         public MDocumentationComment setSince(String s) {
217             tagSince = s;
218             return this;
219         }
220 
221         @Override
222         public MDocumentationComment setThrows(String s) {
223             tagThrows = s;
224             return this;
225         }
226 
227         @Override
228         public MDocumentationComment setVersion(String s) {
229             tagVersion = s;
230             return this;
231         }
232 
233         @Override
234         public CodeWriter toCode(CodeWriter out) {
235             super.toCode(out);
236 
237             out.ensureNewLine();
238             out.write("/**").newLine(); // */
239 
240             MComment.wordWrap(text, MComment.D_COMMENT_LENGTH, " *", out, true);
241 
242             writeTag(tagAuthor, "author", out);
243             writeTag(tagDate, "date", out);
244             writeTag(tagDeprecated, "deprecated", out);
245             writeTag(tagException, "exception", out);
246             writeTag(tagReturn, "return", out);
247             writeTag(tagSerial, "serial", out);
248             writeTag(tagSerialData, "serialData", out);
249             writeTag(tagSerialField, "serialField", out);
250             writeTag(tagSince, "since", out);
251             writeTag(tagThrows, "throws", out);
252             writeTag(tagVersion, "version", out);
253             writeTags(vtagParameter, "param", out);
254             writeTags(vtagSee, "see", out);
255 
256             out.ensureNewLine().space().write("*/");
257 
258             return out;
259         }
260 
261         @Override
262         public void visit(ReplacingVisitor visitor) {
263             super.visit(visitor);
264         }
265 
266         private void writeTag(String tag, String tagLabel, CodeWriter out) {
267             if (tag != null) {
268                 String s = "@" + tagLabel + ' ' + tag;
269                 MComment.wordWrap(s, 55, " *", out, true);
270             }
271         }
272 
273         private void writeTags(List<String> v, String tagLabel, CodeWriter out) {
274             for (String string : v) {
275                 writeTag(string, tagLabel, out);
276             }
277         }
278     }
279 
280     /**
281      * MULTIPLE LINE COMMENT
282      */
283     static final class MMultipleLineComment extends MComment {
284 
285         boolean onlyAtBeginningAndEnd = false;
286 
287         MMultipleLineComment(MVM vm, String text) {
288             super(vm, Comment.MULTI_LINE, text);
289         }
290 
291         MMultipleLineComment(MVM vm, String text, boolean onlyAtBeginningAndEnd) {
292             super(vm, Comment.MULTI_LINE, text);
293             this.onlyAtBeginningAndEnd = onlyAtBeginningAndEnd;
294 
295         }
296 
297         @Override
298         public CodeWriter toCode(CodeWriter out) {
299             super.toCode(out);
300 
301             out.ensureNewLine();
302             out.write("/* ").newLine(); // */
303             if (onlyAtBeginningAndEnd) {
304                 MComment.wordWrap(text, MComment.COMMENT_LENGTH_UNLIMITED, "\t", out, true);
305             } else {
306                 MComment.wordWrap(text, MComment.M_COMMENT_LENGTH, " *", out, true);
307             }
308 
309             out.ensureNewLine().write(" */");
310 
311             return out;
312         }
313 
314         @Override
315         public void visit(ReplacingVisitor visitor) {
316             super.visit(visitor);
317         }
318     }
319 
320     /**
321      * SINGLE LINE COMMENT
322      */
323     static final class MSingleLineComment extends MComment {
324 
325         MSingleLineComment(MVM vm, String text, boolean trailing) {
326             super(vm, trailing ? Comment.TRAILING : Comment.SINGLE_LINE, text);
327         }
328 
329         MSingleLineComment(MVM vm, String text) {
330             this(vm, text, false);
331         }
332 
333         @Override
334         public CodeWriter toCode(CodeWriter out) {
335             super.toCode(out);
336 
337             MComment.wordWrap(text, MComment.S_COMMENT_LENGTH, "//", out, getType() == Comment.SINGLE_LINE);
338 
339             return out;
340         }
341 
342         @Override
343         public void visit(ReplacingVisitor visitor) {
344             super.visit(visitor);
345         }
346     }
347 
348     private static final int S_COMMENT_LENGTH = 30;
349 
350     private static final int M_COMMENT_LENGTH = 180;
351 
352     private static final int D_COMMENT_LENGTH = 180;
353 
354     private static final int COMMENT_LENGTH_UNLIMITED = 500;
355 
356     private static void wordWrap(char[] s, int maxlen, String head, CodeWriter out, boolean startOnNewLine) {
357         int strlen = s.length;
358         int trailer = 0;
359         int leader = 0;
360         int anchor;
361 
362         // Start on a new line
363         if (strlen > 0 && !out.isLineNew()) {
364             if (startOnNewLine) {
365                 out.newLine();
366             } else {
367                 out.write(' ');
368             }
369         }
370 
371         // loop while we look for newline characters.
372         while (leader < strlen) {
373 
374             // are we at the max line length? If so then we need
375             // to write the line thus far (but do so at a good place)
376             if (leader - trailer == maxlen) {
377                 // set the anchor in case we need to retrieve our position
378                 anchor = leader;
379                 // we don't want words to be broken up.
380                 // check to make sure the leader hits a space OR a comma (added
381                 // comma 9/5/00)
382                 word_search: while (s[leader] == ',' || s[leader] != ' ') {
383                     // word_search: while (s[leader] != ' ') {
384                     // move back one character
385                     --leader;
386                     // if it goes all the way back, then too bad, we have to cut
387                     // it...
388                     if (leader == trailer) {
389                         leader = anchor;
390                         break;
391                     }
392                 }
393                 // ok, we've discovered a place to break the line. Now we write
394                 // this much of the output and reset the tracking variables.
395                 out.write(head).space().write(s, trailer, leader - trailer).newLine();
396 
397                 // move the trailer up to the leader
398                 trailer = leader;
399             }
400 
401             // if we've gone this far we need to just make sure that the
402             // character is
403             // not a newline
404             switch (s[leader]) {
405                 case 13: /* CR */{
406                     // in this case we check to see if there is an LF after
407                     // this character. If so this is a Caldera newline
408                     if (s[leader + 1] == 10) {
409                         // flush the line thus far
410                         out.write(head).space().write(s, trailer, leader - trailer).newLine();
411                         // move the leader up two characters such that we skip
412                         // over the newline
413                         trailer = leader + 2;
414                         leader = leader + 2;
415                         // looks like a mac newline. Whadda know?
416                     } else {
417                         // flush the line thus far
418                         out.write(head).space().write(s, trailer, leader - trailer).newLine();
419                         // move the leader up one character such that we skip
420                         // over the newline
421                         trailer = ++leader;
422                     }
423                     break;
424                 }
425                 case 10: /* LF */{
426                     // this is a nix machine
427                     // flush the line thus far
428                     out.write(head).space().write(s, trailer, leader - trailer).newLine();
429                     // move the leader up one character such that we skip over
430                     // the newline
431                     trailer = ++leader;
432                     // bust out
433                     break;
434                 }
435                 default: {
436                     // just advance the leader
437                     leader++;
438                 }
439             }
440         }
441 
442         // flush the rest of the line to the writer
443         out.write(head).space().write(s, trailer, leader - trailer).newLine();
444     }
445 
446     /**
447      * <P>
448      * Breaks the given String into lines with given length int tabbed to a
449      * distance given int tab and prefixed with an asterisk and a space.
450      * Therefore,
451      * <P>
452      * {@code wordWrap("How now brown cow", 5, 0);}
453      * <P>
454      * returns:
455      * <P>
456      * How<BR>
457      * now<BR>
458      * brown<BR>
459      * cow<BR>
460      */
461     private static void wordWrap(String s, int maxlen, String head, CodeWriter out, boolean startOnNewLine) {
462         wordWrap(s.toCharArray(), maxlen, head, out, startOnNewLine);
463     }
464 
465     private final int type;
466 
467     String text;
468 
469     MComment(MVM vm, int type, String text) {
470         super(vm);
471         this.type = type;
472         this.text = text;
473     }
474 
475     @Override
476     public String getText() {
477         return text;
478     }
479 
480     @Override
481     public MComment setText(String text) {
482         this.text = text;
483         return this;
484     }
485 
486     /**
487      * CLASS METHODS
488      */
489     @Deprecated
490     @Override
491     public int type() {
492         return getType();
493     }
494 
495     @Override
496     public int getType() {
497         return type;
498     }
499 }