• 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 PythonTarget extends Target {
45     /** Target must be able to override the labels used for token types */
getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype)46     public String getTokenTypeAsTargetLabel(CodeGenerator generator,
47 					    int ttype) {
48 	// use ints for predefined types;
49 	// <invalid> <EOR> <DOWN> <UP>
50 	if ( ttype >= 0 && ttype <= 3 ) {
51 	    return String.valueOf(ttype);
52 	}
53 
54 	String name = generator.grammar.getTokenDisplayName(ttype);
55 
56 	// If name is a literal, return the token type instead
57 	if ( name.charAt(0)=='\'' ) {
58 	    return String.valueOf(ttype);
59 	}
60 
61 	return name;
62     }
63 
getTargetCharLiteralFromANTLRCharLiteral( CodeGenerator generator, String literal)64     public String getTargetCharLiteralFromANTLRCharLiteral(
65             CodeGenerator generator,
66             String literal) {
67 	int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
68 	return String.valueOf(c);
69     }
70 
splitLines(String text)71     private List splitLines(String text) {
72 		ArrayList l = new ArrayList();
73 		int idx = 0;
74 
75 		while ( true ) {
76 			int eol = text.indexOf("\n", idx);
77 			if ( eol == -1 ) {
78 				l.add(text.substring(idx));
79 				break;
80 			}
81 			else {
82 				l.add(text.substring(idx, eol+1));
83 				idx = eol+1;
84 			}
85 		}
86 
87 		return l;
88     }
89 
postProcessAction(List chunks, Token actionToken)90     public List postProcessAction(List chunks, Token actionToken) {
91 		/* TODO
92 		   - check for and report TAB usage
93 		 */
94 
95 		//System.out.println("\n*** Action at " + actionToken.getLine() + ":" + actionToken.getColumn());
96 
97 		/* First I create a new list of chunks. String chunks are splitted into
98 		   lines and some whitespace my be added at the beginning.
99 
100 		   As a result I get a list of chunks
101 		   - where the first line starts at column 0
102 		   - where every LF is at the end of a string chunk
103 		*/
104 
105 		List nChunks = new ArrayList();
106 		for (int i = 0; i < chunks.size(); i++) {
107 			Object chunk = chunks.get(i);
108 
109 			if ( chunk instanceof String ) {
110 				String text = (String)chunks.get(i);
111 				if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) {
112 					// first chunk and some 'virtual' WS at beginning
113 					// prepend to this chunk
114 
115 					String ws = "";
116 					for ( int j = 0 ; j < actionToken.getCharPositionInLine() ; j++ ) {
117 						ws += " ";
118 					}
119 					text = ws + text;
120 				}
121 
122 				List parts = splitLines(text);
123 				for ( int j = 0 ; j < parts.size() ; j++ ) {
124 					chunk = parts.get(j);
125 					nChunks.add(chunk);
126 				}
127 			}
128 			else {
129 				if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) {
130 					// first chunk and some 'virtual' WS at beginning
131 					// add as a chunk of its own
132 
133 					String ws = "";
134 					for ( int j = 0 ; j <= actionToken.getCharPositionInLine() ; j++ ) {
135 						ws += " ";
136 					}
137 					nChunks.add(ws);
138 				}
139 
140 				nChunks.add(chunk);
141 			}
142 		}
143 
144 		int lineNo = actionToken.getLine();
145 		int col = 0;
146 
147 		// strip trailing empty lines
148 		int lastChunk = nChunks.size() - 1;
149 		while ( lastChunk > 0
150 				&& nChunks.get(lastChunk) instanceof String
151 				&& ((String)nChunks.get(lastChunk)).trim().length() == 0 )
152 			lastChunk--;
153 
154 		// string leading empty lines
155 		int firstChunk = 0;
156 		while ( firstChunk <= lastChunk
157 				&& nChunks.get(firstChunk) instanceof String
158 				&& ((String)nChunks.get(firstChunk)).trim().length() == 0
159 				&& ((String)nChunks.get(firstChunk)).endsWith("\n") ) {
160 			lineNo++;
161 			firstChunk++;
162 		}
163 
164 		int indent = -1;
165 		for ( int i = firstChunk ; i <= lastChunk ; i++ ) {
166 			Object chunk = nChunks.get(i);
167 
168 			//System.out.println(lineNo + ":" + col + " " + quote(chunk.toString()));
169 
170 			if ( chunk instanceof String ) {
171 				String text = (String)chunk;
172 
173 				if ( col == 0 ) {
174 					if ( indent == -1 ) {
175 						// first non-blank line
176 						// count number of leading whitespaces
177 
178 						indent = 0;
179 						for ( int j = 0; j < text.length(); j++ ) {
180 							if ( !Character.isWhitespace(text.charAt(j)) )
181 								break;
182 
183 							indent++;
184 						}
185 					}
186 
187 					if ( text.length() >= indent ) {
188 						int j;
189 						for ( j = 0; j < indent ; j++ ) {
190 							if ( !Character.isWhitespace(text.charAt(j)) ) {
191 								// should do real error reporting here...
192 								System.err.println("Warning: badly indented line " + lineNo + " in action:");
193 								System.err.println(text);
194 								break;
195 							}
196 						}
197 
198 						nChunks.set(i, text.substring(j));
199 					}
200 					else if ( text.trim().length() > 0 ) {
201 						// should do real error reporting here...
202 						System.err.println("Warning: badly indented line " + lineNo + " in action:");
203 						System.err.println(text);
204 					}
205 				}
206 
207 				if ( text.endsWith("\n") ) {
208 					lineNo++;
209 					col = 0;
210 				}
211 				else {
212 					col += text.length();
213 				}
214 			}
215 			else {
216 				// not really correct, but all I need is col to increment...
217 				col += 1;
218 			}
219 		}
220 
221 		return nChunks;
222     }
223 }
224