• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2010 Terence Parr
4  *  All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *  1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *  3. The name of the author may not be used to endorse or promote products
15  *      derived from this software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30 
31 Please excuse my obvious lack of Java experience. The code here is probably
32 full of WTFs - though IMHO Java is the Real WTF(TM) here...
33 
34  */
35 
36 package org.antlr.codegen;
37 
38 import org.antlr.runtime.Token;
39 import org.antlr.tool.Grammar;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 public class Python3Target extends Target {
45     @Override
useBaseTemplatesForSynPredFragments()46     public boolean useBaseTemplatesForSynPredFragments() {
47         return false;
48     }
49 
50     /** Target must be able to override the labels used for token types */
51 	@Override
getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype)52     public String getTokenTypeAsTargetLabel(CodeGenerator generator,
53 					    int ttype) {
54 	// use ints for predefined types;
55 	// <invalid> <EOR> <DOWN> <UP>
56 	if ( ttype >= 0 && ttype <= 3 ) {
57 	    return String.valueOf(ttype);
58 	}
59 
60 	String name = generator.grammar.getTokenDisplayName(ttype);
61 
62 	// If name is a literal, return the token type instead
63 	if ( name.charAt(0)=='\'' ) {
64 	    return String.valueOf(ttype);
65 	}
66 
67 	return name;
68     }
69 
70 	@Override
getTargetCharLiteralFromANTLRCharLiteral( CodeGenerator generator, String literal)71     public String getTargetCharLiteralFromANTLRCharLiteral(
72             CodeGenerator generator,
73             String literal) {
74 	int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
75 	return String.valueOf(c);
76     }
77 
splitLines(String text)78     private List<String> splitLines(String text) {
79 		ArrayList<String> l = new ArrayList<String>();
80 		int idx = 0;
81 
82 		while ( true ) {
83 			int eol = text.indexOf("\n", idx);
84 			if ( eol == -1 ) {
85 				l.add(text.substring(idx));
86 				break;
87 			}
88 			else {
89 				l.add(text.substring(idx, eol+1));
90 				idx = eol+1;
91 			}
92 		}
93 
94 		return l;
95     }
96 
97 	@Override
postProcessAction(List<Object> chunks, Token actionToken)98     public List<Object> postProcessAction(List<Object> chunks, Token actionToken) {
99 		/* TODO
100 		   - check for and report TAB usage
101 		 */
102 
103 		//System.out.println("\n*** Action at " + actionToken.getLine() + ":" + actionToken.getColumn());
104 
105 		/* First I create a new list of chunks. String chunks are splitted into
106 		   lines and some whitespace my be added at the beginning.
107 
108 		   As a result I get a list of chunks
109 		   - where the first line starts at column 0
110 		   - where every LF is at the end of a string chunk
111 		*/
112 
113 		List<Object> nChunks = new ArrayList<Object>();
114 		for (int i = 0; i < chunks.size(); i++) {
115 			Object chunk = chunks.get(i);
116 
117 			if ( chunk instanceof String ) {
118 				String text = (String)chunks.get(i);
119 				if ( nChunks.isEmpty() && actionToken.getCharPositionInLine() >= 0 ) {
120 					// first chunk and some 'virtual' WS at beginning
121 					// prepend to this chunk
122 
123 					String ws = "";
124 					for ( int j = 0 ; j < actionToken.getCharPositionInLine() ; j++ ) {
125 						ws += " ";
126 					}
127 					text = ws + text;
128 				}
129 
130 				nChunks.addAll(splitLines(text));
131 			}
132 			else {
133 				if ( nChunks.isEmpty() && actionToken.getCharPositionInLine() >= 0 ) {
134 					// first chunk and some 'virtual' WS at beginning
135 					// add as a chunk of its own
136 
137 					String ws = "";
138 					for ( int j = 0 ; j <= actionToken.getCharPositionInLine() ; j++ ) {
139 						ws += " ";
140 					}
141 					nChunks.add(ws);
142 				}
143 
144 				nChunks.add(chunk);
145 			}
146 		}
147 
148 		int lineNo = actionToken.getLine();
149 		int col = 0;
150 
151 		// strip trailing empty lines
152 		int lastChunk = nChunks.size() - 1;
153 		while ( lastChunk > 0
154 				&& nChunks.get(lastChunk) instanceof String
155 				&& ((String)nChunks.get(lastChunk)).trim().length() == 0 )
156 			lastChunk--;
157 
158 		// string leading empty lines
159 		int firstChunk = 0;
160 		while ( firstChunk <= lastChunk
161 				&& nChunks.get(firstChunk) instanceof String
162 				&& ((String)nChunks.get(firstChunk)).trim().length() == 0
163 				&& ((String)nChunks.get(firstChunk)).endsWith("\n") ) {
164 			lineNo++;
165 			firstChunk++;
166 		}
167 
168 		int indent = -1;
169 		for ( int i = firstChunk ; i <= lastChunk ; i++ ) {
170 			Object chunk = nChunks.get(i);
171 
172 			//System.out.println(lineNo + ":" + col + " " + quote(chunk.toString()));
173 
174 			if ( chunk instanceof String ) {
175 				String text = (String)chunk;
176 
177 				if ( col == 0 ) {
178 					if ( indent == -1 ) {
179 						// first non-blank line
180 						// count number of leading whitespaces
181 
182 						indent = 0;
183 						for ( int j = 0; j < text.length(); j++ ) {
184 							if ( !Character.isWhitespace(text.charAt(j)) )
185 								break;
186 
187 							indent++;
188 						}
189 					}
190 
191 					if ( text.length() >= indent ) {
192 						int j;
193 						for ( j = 0; j < indent ; j++ ) {
194 							if ( !Character.isWhitespace(text.charAt(j)) ) {
195 								// should do real error reporting here...
196 								System.err.println("Warning: badly indented line " + lineNo + " in action:");
197 								System.err.println(text);
198 								break;
199 							}
200 						}
201 
202 						nChunks.set(i, text.substring(j));
203 					}
204 					else if ( text.trim().length() > 0 ) {
205 						// should do real error reporting here...
206 						System.err.println("Warning: badly indented line " + lineNo + " in action:");
207 						System.err.println(text);
208 					}
209 				}
210 
211 				if ( text.endsWith("\n") ) {
212 					lineNo++;
213 					col = 0;
214 				}
215 				else {
216 					col += text.length();
217 				}
218 			}
219 			else {
220 				// not really correct, but all I need is col to increment...
221 				col += 1;
222 			}
223 		}
224 
225 		return nChunks;
226     }
227 }
228