1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/*
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * [The "BSD license"]
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Copyright (c) 2010 Terence Parr
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  All rights reserved.
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Redistribution and use in source and binary forms, with or without
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  modification, are permitted provided that the following conditions
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  are met:
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  1. Redistributions of source code must retain the above copyright
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      notice, this list of conditions and the following disclaimer.
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  2. Redistributions in binary form must reproduce the above copyright
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      notice, this list of conditions and the following disclaimer in the
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      documentation and/or other materials provided with the distribution.
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  3. The name of the author may not be used to endorse or promote products
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      derived from this software without specific prior written permission.
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/*
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
31324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverPlease excuse my obvious lack of Java experience. The code here is probably
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfull of WTFs - though IMHO Java is the Real WTF(TM) here...
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpackage org.antlr.codegen;
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.runtime.Token;
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.tool.Grammar;
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.util.ArrayList;
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.util.List;
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpublic class PythonTarget extends Target {
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Target must be able to override the labels used for token types */
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    public String getTokenTypeAsTargetLabel(CodeGenerator generator,
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					    int ttype) {
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	// use ints for predefined types;
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	// <invalid> <EOR> <DOWN> <UP>
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	if ( ttype >= 0 && ttype <= 3 ) {
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    return String.valueOf(ttype);
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	String name = generator.grammar.getTokenDisplayName(ttype);
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	// If name is a literal, return the token type instead
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	if ( name.charAt(0)=='\'' ) {
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    return String.valueOf(ttype);
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	return name;
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    public String getTargetCharLiteralFromANTLRCharLiteral(
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            CodeGenerator generator,
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            String literal) {
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	return String.valueOf(c);
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    private List splitLines(String text) {
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		ArrayList l = new ArrayList();
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int idx = 0;
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		while ( true ) {
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			int eol = text.indexOf("\n", idx);
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( eol == -1 ) {
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				l.add(text.substring(idx));
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				break;
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			else {
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				l.add(text.substring(idx, eol+1));
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				idx = eol+1;
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return l;
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    public List postProcessAction(List chunks, Token actionToken) {
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		/* TODO
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		   - check for and report TAB usage
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 */
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		//System.out.println("\n*** Action at " + actionToken.getLine() + ":" + actionToken.getColumn());
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		/* First I create a new list of chunks. String chunks are splitted into
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		   lines and some whitespace my be added at the beginning.
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		   As a result I get a list of chunks
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		   - where the first line starts at column 0
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		   - where every LF is at the end of a string chunk
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		*/
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		List nChunks = new ArrayList();
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		for (int i = 0; i < chunks.size(); i++) {
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			Object chunk = chunks.get(i);
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( chunk instanceof String ) {
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				String text = (String)chunks.get(i);
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) {
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					// first chunk and some 'virtual' WS at beginning
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					// prepend to this chunk
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					String ws = "";
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					for ( int j = 0 ; j < actionToken.getCharPositionInLine() ; j++ ) {
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						ws += " ";
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					}
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					text = ws + text;
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				List parts = splitLines(text);
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				for ( int j = 0 ; j < parts.size() ; j++ ) {
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					chunk = parts.get(j);
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					nChunks.add(chunk);
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			else {
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) {
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					// first chunk and some 'virtual' WS at beginning
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					// add as a chunk of its own
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					String ws = "";
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					for ( int j = 0 ; j <= actionToken.getCharPositionInLine() ; j++ ) {
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						ws += " ";
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					}
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					nChunks.add(ws);
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				nChunks.add(chunk);
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int lineNo = actionToken.getLine();
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int col = 0;
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		// strip trailing empty lines
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int lastChunk = nChunks.size() - 1;
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		while ( lastChunk > 0
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				&& nChunks.get(lastChunk) instanceof String
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				&& ((String)nChunks.get(lastChunk)).trim().length() == 0 )
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			lastChunk--;
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		// string leading empty lines
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int firstChunk = 0;
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		while ( firstChunk <= lastChunk
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				&& nChunks.get(firstChunk) instanceof String
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				&& ((String)nChunks.get(firstChunk)).trim().length() == 0
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				&& ((String)nChunks.get(firstChunk)).endsWith("\n") ) {
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			lineNo++;
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			firstChunk++;
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int indent = -1;
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		for ( int i = firstChunk ; i <= lastChunk ; i++ ) {
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			Object chunk = nChunks.get(i);
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			//System.out.println(lineNo + ":" + col + " " + quote(chunk.toString()));
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( chunk instanceof String ) {
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				String text = (String)chunk;
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( col == 0 ) {
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					if ( indent == -1 ) {
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						// first non-blank line
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						// count number of leading whitespaces
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						indent = 0;
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						for ( int j = 0; j < text.length(); j++ ) {
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver							if ( !Character.isWhitespace(text.charAt(j)) )
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver								break;
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver							indent++;
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						}
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					}
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					if ( text.length() >= indent ) {
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						int j;
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						for ( j = 0; j < indent ; j++ ) {
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver							if ( !Character.isWhitespace(text.charAt(j)) ) {
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver								// should do real error reporting here...
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver								System.err.println("Warning: badly indented line " + lineNo + " in action:");
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver								System.err.println(text);
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver								break;
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver							}
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						}
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						nChunks.set(i, text.substring(j));
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					}
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					else if ( text.trim().length() > 0 ) {
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						// should do real error reporting here...
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						System.err.println("Warning: badly indented line " + lineNo + " in action:");
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver						System.err.println(text);
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					}
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( text.endsWith("\n") ) {
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					lineNo++;
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					col = 0;
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				else {
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver					col += text.length();
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				}
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			else {
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				// not really correct, but all I need is col to increment...
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				col += 1;
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return nChunks;
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
224