Home | History | Annotate | Download | only in codegen
      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 */
     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 
     64     public String getTargetCharLiteralFromANTLRCharLiteral(
     65             CodeGenerator generator,
     66             String literal) {
     67 	int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
     68 	return String.valueOf(c);
     69     }
     70 
     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 
     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