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