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