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