source: default/trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfFormatterVisitor.java @ 27

Last change on this file since 27 was 27, checked in by zeiss, 14 years ago
  • Property svn:mime-type set to text/plain
File size: 13.1 KB
Line 
1package de.ugoe.cs.swe.bnftools.ui.formatter;
2
3import java.util.ArrayList;
4
5import org.eclipse.emf.ecore.EObject;
6import org.eclipse.xtext.parsetree.AbstractNode;
7import org.eclipse.xtext.parsetree.CompositeNode;
8import org.eclipse.xtext.parsetree.LeafNode;
9import org.eclipse.xtext.parsetree.NodeUtil;
10
11import de.ugoe.cs.swe.bnftools.ebnf.Atom;
12import de.ugoe.cs.swe.bnftools.ebnf.BnfEntry;
13import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList;
14import de.ugoe.cs.swe.bnftools.ebnf.DeltaEntry;
15import de.ugoe.cs.swe.bnftools.ebnf.EtsiBnf;
16import de.ugoe.cs.swe.bnftools.ebnf.ExtRule;
17import de.ugoe.cs.swe.bnftools.ebnf.GlobalCombinator;
18import de.ugoe.cs.swe.bnftools.ebnf.GroupedSequence;
19import de.ugoe.cs.swe.bnftools.ebnf.HookCombinator;
20import de.ugoe.cs.swe.bnftools.ebnf.Import;
21import de.ugoe.cs.swe.bnftools.ebnf.ImportSection;
22import de.ugoe.cs.swe.bnftools.ebnf.MergeEntry;
23import de.ugoe.cs.swe.bnftools.ebnf.MergeRule;
24import de.ugoe.cs.swe.bnftools.ebnf.OptionalSequence;
25import de.ugoe.cs.swe.bnftools.ebnf.RepeatedSequence;
26import de.ugoe.cs.swe.bnftools.ebnf.Rule;
27import de.ugoe.cs.swe.bnftools.ebnf.RuleCombinator;
28import de.ugoe.cs.swe.bnftools.ebnf.RuleReference;
29import de.ugoe.cs.swe.bnftools.ebnf.SectionHeading;
30import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition;
31import de.ugoe.cs.swe.bnftools.ebnf.StringRule;
32import de.ugoe.cs.swe.bnftools.ebnf.Term;
33import de.ugoe.cs.swe.bnftools.visitor.EbnfVisitor;
34
35public class EbnfFormatterVisitor extends EbnfVisitor {
36        private StringBuffer buf;
37        private FormatterConfig config;
38        private int bufferPositionFormattedTextNoWhitespaces = 0;
39        private int bufferPositionOriginalText = 0;
40        private int allCommentsPosition = 0;
41        private ArrayList<LeafNode> allComments = new ArrayList<LeafNode>();
42       
43        private boolean lastWasSectionHeading=false;
44        private CompositeNode parserEtsiBnfNode;
45        private String originalText;
46        private int bufferPositionFormattedText;
47        private String formattedText;
48        private String formattedTextNoWhitespaces;
49        private String originalTextNoWhitespaces;
50       
51        public EbnfFormatterVisitor(EObject rootNode, FormatterConfig config) {
52                super(rootNode);
53                this.config = config;
54                buf = new StringBuffer();
55        }
56
57        public EbnfFormatterVisitor(FormatterConfig config) {
58                this.config = config;
59                buf = new StringBuffer();
60        }
61
62        public StringBuffer getBuf() {
63                return buf;
64        }
65
66        private boolean isCommentNode(LeafNode node) {
67                if ((node.getText().trim().startsWith("//") || node.getText().trim().startsWith("/*")) && (node.isHidden()))
68                        return true;
69                return false;
70        }
71       
72        private void collectAllComments(CompositeNode node) {
73                for (int i=0; i < node.getChildren().size(); i++) {
74                        AbstractNode currentNode = node.getChildren().get(i);
75                        if (currentNode instanceof LeafNode) {
76                                LeafNode leafNode = (LeafNode) currentNode;
77                                if (isCommentNode(leafNode)) {
78                                        allComments.add(leafNode);
79                                }
80                        }
81                       
82                        if (currentNode instanceof CompositeNode) {
83                                collectAllComments((CompositeNode) currentNode);
84                        }
85                }
86        }
87
88        private boolean isSingleLineComment(String str) {
89                if (str.startsWith("//"))
90                        return true;
91                return false;
92        }
93       
94        private boolean isMultiLineComment(String str) {
95                if (str.startsWith("/*"))
96                        return true;
97                return false;
98        }
99
100        private boolean isWhitespace(char ch) {
101                if ((ch==' ') || (ch == '\t') || (ch == '\n') || (ch == '\r'))
102                        return true;
103                return false;
104        }
105       
106        private void skipWhitespacesOriginalText() {
107                while (bufferPositionOriginalText < originalText.length() && isWhitespace(originalText.charAt(bufferPositionOriginalText))) {
108                        bufferPositionOriginalText++;
109                }
110        }
111
112        private void skipWhitespacesFormattedText(StringBuffer result) {
113                while (bufferPositionFormattedText < formattedText.length() && isWhitespace(formattedText.charAt(bufferPositionFormattedText))) {
114                        result.append(formattedText.substring(bufferPositionFormattedText, bufferPositionFormattedText+1));
115                        bufferPositionFormattedText++;
116                }
117        }
118
119        private boolean isSingleLineCommentNext(String str, int position) {
120                if ((str.charAt(position) == '/') && (str.charAt(position) == '/'))
121                        return true;
122                return false;
123        }
124       
125        private boolean isMultiLineCommentNext(String str, int position) {
126                if ((str.charAt(position) == '/') && (str.charAt(position) == '*'))
127                        return true;
128                return false;
129        }
130               
131        private boolean isCommentNext(String str, int position) {
132                if (isSingleLineCommentNext(str, position) || isMultiLineCommentNext(str, position))
133                        return true;
134                else
135                        return false;
136        }
137       
138        private String scanBackWhitespaces(String str, int position) {
139                StringBuffer whiteSpaces = new StringBuffer();
140                int currentPosition = position;
141                while (isWhitespace(str.charAt(currentPosition))) {
142                        whiteSpaces.append(str.charAt(currentPosition));
143                        currentPosition--;
144                }
145                return whiteSpaces.toString();
146        }
147       
148        private String stripEndingNewline(String str) {
149                int position = str.length() - 1;
150                while ((str.charAt(position) == '\n') || (str.charAt(position) == '\r')) {
151                        position--;
152                }
153                return str.substring(0, position + 1);
154        }
155       
156        private int scanBackNewlinesCount(String str, int position) {
157                int newLinesCount = 0;
158                int currentPosition = position;
159                while ((str.charAt(currentPosition) == '\n') || (str.charAt(currentPosition) == '\r')) {
160                        if (str.charAt(currentPosition) == '\n') {
161                                if (str.charAt(currentPosition - 1) == '\r') {
162                                        currentPosition -= 2;
163                                } else {
164                                        currentPosition -= 1;
165                                }
166                                newLinesCount++;
167                        } else if (str.charAt(currentPosition) == '\r') {
168                                currentPosition -= 1;
169                                newLinesCount++;
170                        }
171                }
172               
173                return newLinesCount;
174        }
175       
176        private void weaveComments() {
177//              if (true) {
178//                      StringBuffer result = new StringBuffer();
179//                      result.append(buf.toString());
180//                      buf = result;
181//                      return;
182//              }
183               
184                bufferPositionOriginalText = 0;
185                bufferPositionFormattedTextNoWhitespaces = 0;
186                bufferPositionFormattedText = 0;
187               
188                StringBuffer result = new StringBuffer();
189                formattedTextNoWhitespaces = buf.toString().replaceAll("[ \t\n\r]", "");
190                formattedText = buf.toString();
191               
192                while (bufferPositionFormattedTextNoWhitespaces <= formattedTextNoWhitespaces.length()) {
193                        skipWhitespacesOriginalText();
194                        skipWhitespacesFormattedText(result);
195                       
196                        if (!(bufferPositionOriginalText < originalText.length()))
197                                break;
198                       
199                        char formattedPositionNoWhitespaces;
200                        if (bufferPositionFormattedTextNoWhitespaces == formattedTextNoWhitespaces.length()) {
201                                formattedPositionNoWhitespaces = ' ';
202                        } else {
203                                formattedPositionNoWhitespaces = formattedTextNoWhitespaces.charAt(bufferPositionFormattedTextNoWhitespaces);
204                        }
205                        char originalPosition = originalText.charAt(bufferPositionOriginalText);
206
207                        if (formattedPositionNoWhitespaces != originalPosition) {
208                                if (formattedPositionNoWhitespaces == ';') { // formatted text always outputs the optional semicolon, skip it if necessary
209                                        bufferPositionFormattedTextNoWhitespaces++;
210                                        bufferPositionFormattedText++;
211                                } else if (isCommentNext(originalText, bufferPositionOriginalText)) {
212                                        LeafNode currentComment = allComments.get(allCommentsPosition);
213                                        if (currentComment.getTotalOffset() == bufferPositionOriginalText) {
214                                                if (isMultiLineComment(currentComment.getText())) {
215                                                        int newLinesCount = scanBackNewlinesCount(originalText, bufferPositionOriginalText-1);
216                                                        if (newLinesCount > 0) {
217                                                                if (scanBackNewlinesCount(result.toString(), result.toString().length()-1) == 0) {
218                                                                        result.append("\n\n");
219                                                                }
220                                                               
221                                                                result.append(currentComment.getText());
222                                                                result.append("\n");
223                                                        } else {
224                                                                String lastWhiteSpaces = scanBackWhitespaces(result.toString(), result.toString().length()-1);
225                                                                result.delete(result.toString().length() - lastWhiteSpaces.length(), result.toString().length());
226                                                                result.append(" " + stripEndingNewline(currentComment.getText()));
227                                                                result.append(lastWhiteSpaces);
228                                                        }
229                                                } else if (isSingleLineComment(currentComment.getText())) {
230                                                        int newLinesCount = scanBackNewlinesCount(originalText, bufferPositionOriginalText-1);
231                                                        String lastWhiteSpaces = scanBackWhitespaces(result.toString(), result.toString().length()-1);
232                                                        result.delete(result.toString().length() - lastWhiteSpaces.length(), result.toString().length());
233                                                        if (newLinesCount > 0) {
234                                                                result.append("\n\n" + stripEndingNewline(currentComment.getText()));
235                                                        } else {
236                                                                result.append(" " + stripEndingNewline(currentComment.getText()));
237                                                        }
238                                                        result.append(lastWhiteSpaces);
239                                                }
240                                                bufferPositionOriginalText+=currentComment.getLength();
241                                                allCommentsPosition++;
242                                        }
243                                } else { // disaster handling: return original unformatted text!
244                                        buf = new StringBuffer();
245                                        buf.append(originalText);
246                                        return;
247                                }
248                        } else {
249                                result.append(formattedText.substring(bufferPositionFormattedText, bufferPositionFormattedText+1));
250                                bufferPositionOriginalText++;
251                                bufferPositionFormattedText++;
252                                bufferPositionFormattedTextNoWhitespaces++;
253                        }
254                }
255                buf = result;
256               
257        }
258
259        private void newLine() {
260                buf.append("\n");
261        }
262       
263        private void text(String str) {
264                buf.append(str);
265        }
266
267        private void space() {
268                buf.append(" ");
269        }
270
271        // -----------------------------------------------------------------------------
272
273        protected void visitBefore(EtsiBnf node) {
274                parserEtsiBnfNode = NodeUtil.getNodeAdapter(node).getParserNode();
275                collectAllComments(parserEtsiBnfNode);
276                originalText = NodeUtil.getNodeAdapter(node).getParserNode().serialize();
277                originalTextNoWhitespaces = originalText.replaceAll("[ \t\n\r]", "");
278               
279                //System.out.println(allComments.toString());
280                text("grammar " + node.getName());
281                if (node.getType() != null)
282                        text(node.getType());
283                text(";");
284
285                newLine();
286                newLine();
287        }
288
289        protected void visitAfter(EtsiBnf node) {
290                weaveComments();
291        }
292
293        protected void visitBefore(ImportSection node) {
294        }
295
296        protected void visitAfter(ImportSection node) {
297                newLine();
298        }
299
300        protected void visitBefore(BnfEntry node) {
301        }
302
303        protected void visitAfter(BnfEntry node) {
304        }
305       
306        protected void visitBefore(DeltaEntry node) {
307        }
308
309        protected void visitAfter(DeltaEntry node) {
310        }
311       
312        protected void visitBefore(MergeEntry node) {
313        }
314
315        protected void visitAfter(MergeEntry node) {
316        }
317       
318        protected void visitBefore(Atom node) {
319        }
320
321        protected void visitAfter(Atom node) {
322        }
323
324        protected void visitBefore(Term node) {
325        }
326
327        protected void visitAfter(Term node) {
328                if (!isLastElement())
329                        space();
330        }
331
332        protected void visitBefore(DefinitionList node) {
333        }
334
335        protected void visitAfter(DefinitionList node) {
336        }
337
338        protected void visitBefore(ExtRule node) {
339        }
340
341        protected void visitAfter(ExtRule node) {
342        }
343
344        protected void visitBefore(GlobalCombinator node) {
345        }
346
347        protected void visitAfter(GlobalCombinator node) {
348        }
349
350        protected void visitBefore(GroupedSequence node) {
351                text("(");
352        }
353
354        protected void visitAfter(GroupedSequence node) {
355                text(")");
356        }
357
358        protected void visitBefore(HookCombinator node) {
359        }
360
361        protected void visitAfter(HookCombinator node) {
362        }
363
364        protected void visitBefore(Import node) {
365                text("import \"" + node.getImportURI() + "\";");
366                newLine();
367        }
368
369        protected void visitAfter(Import node) {
370        }
371
372        protected void visitBefore(MergeRule node) {
373        }
374
375        protected void visitAfter(MergeRule node) {
376        }
377
378        protected void visitBefore(OptionalSequence node) {
379                text("[");
380        }
381
382        protected void visitAfter(OptionalSequence node) {
383                text("]");
384        }
385
386        protected void visitBefore(RepeatedSequence node) {
387                text("{");
388        }
389
390        protected void visitAfter(RepeatedSequence node) {
391                text("}");
392                if (node.isMorethanonce())
393                        text("+");
394        }
395
396        protected void visitBefore(Rule node) {
397                if (lastWasSectionHeading)
398                        newLine();
399               
400                lastWasSectionHeading=false;
401
402                if (node.getRulenumber() > 0)
403                        text(node.getRulenumber() + ". ");
404               
405                text(node.getName() + " ::= ");
406        }
407
408        protected void visitAfter(Rule node) {
409                text(";");
410                newLine();
411        }
412
413        protected void visitBefore(RuleCombinator node) {
414        }
415
416        protected void visitAfter(RuleCombinator node) {
417        }
418
419        protected void visitBefore(RuleReference node) {
420                text(node.getRuleref().getName());
421        }
422
423        protected void visitAfter(RuleReference node) {
424        }
425
426        protected void visitBefore(SectionHeading node) {
427                if (!lastWasSectionHeading && !buf.substring(buf.length()-2).equals("\n\n"))
428                        newLine();
429               
430                lastWasSectionHeading=true;
431//              if (!lastWasSectionHeading || !buf.substring(buf.length()-2).equals("\n\n"))
432//              if (!buf.substring(buf.length()-2).equals("\n\n"))
433//                      buf.append("\n");
434               
435                text(node.getSectionHeader());
436        }
437
438        protected void visitAfter(SectionHeading node) {
439        }
440
441        protected void visitBefore(SingleDefinition node) {
442        }
443
444        protected void visitAfter(SingleDefinition node) {
445                if (!isLastElement())
446                        text(" | ");
447               
448        }
449
450        protected void visitBefore(StringRule node) {
451                if (node.getLiteral() != null)
452                        text("\"" + node.getLiteral() + "\"");
453                else if (node.getColon() != null)
454                        text("\"\"\"");
455        }
456
457        protected void visitAfter(StringRule node) {
458        }
459       
460}
Note: See TracBrowser for help on using the repository browser.