1 16 package com.google.gwt.dev.util; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.core.ext.typeinfo.JMethod; 21 import com.google.gwt.core.ext.typeinfo.JParameter; 22 import com.google.gwt.core.ext.typeinfo.JType; 23 import com.google.gwt.dev.js.JsParser; 24 import com.google.gwt.dev.js.JsParserException; 25 import com.google.gwt.dev.js.JsSourceGenerationVisitor; 26 import com.google.gwt.dev.js.JsParserException.SourceDetail; 27 import com.google.gwt.dev.js.ast.JsBlock; 28 import com.google.gwt.dev.js.ast.JsContext; 29 import com.google.gwt.dev.js.ast.JsExprStmt; 30 import com.google.gwt.dev.js.ast.JsExpression; 31 import com.google.gwt.dev.js.ast.JsFunction; 32 import com.google.gwt.dev.js.ast.JsNameRef; 33 import com.google.gwt.dev.js.ast.JsNode; 34 import com.google.gwt.dev.js.ast.JsProgram; 35 import com.google.gwt.dev.js.ast.JsStatements; 36 import com.google.gwt.dev.shell.JavaScriptHost; 37 38 import java.io.IOException ; 39 import java.io.StringReader ; 40 41 44 public class Jsni { 45 46 49 public static class Interval { 50 51 public final int end; 52 53 public final int start; 54 55 public Interval(int start, int end) { 56 this.start = start; 57 this.end = end; 58 } 59 } 60 61 91 private static class JsSourceGenWithJsniIdentFixup extends 92 JsSourceGenerationVisitor { 93 private final TextOutput out; 94 95 public JsSourceGenWithJsniIdentFixup(TextOutput out) { 96 super(out); 97 this.out = out; 98 } 99 100 public boolean visit(JsNameRef x, JsContext ctx) { 101 String ident = x.getIdent(); 102 if (ident.startsWith("@")) { 103 JsExpression q = x.getQualifier(); 104 if (q != null) { 105 accept(q); 106 out.print("[\""); 107 out.print(ident); 108 out.print("\"]"); 109 } else { 110 out.print("__static[\""); 111 out.print(ident); 112 out.print("\"]"); 113 } 114 return false; 115 } else { 116 return super.visit(x, ctx); 117 } 118 } 119 } 120 121 public static final String JAVASCRIPTHOST_NAME = JavaScriptHost.class.getName(); 122 123 public static final String JSNI_BLOCK_END = "}-*/"; 124 125 public static final String JSNI_BLOCK_START = "/*-{"; 126 127 130 public static String buildArgList(JMethod method) { 131 StringBuffer sb = new StringBuffer (); 132 sb.append("new Object[]{"); 133 134 JParameter[] params = method.getParameters(); 135 for (int i = 0; i < params.length; ++i) { 136 if (i > 0) { 137 sb.append(", "); 138 } 139 140 JType type = params[i].getType(); 141 String typeName = type.getQualifiedSourceName(); 142 143 if ((type.isArray() == null) && (type.isPrimitive() != null)) { 144 if (typeName.equals("boolean")) { 147 sb.append("new Boolean(" + params[i].getName() + ")"); 148 } else if (typeName.equals("byte")) { 149 sb.append("new Byte(" + params[i].getName() + ")"); 150 } else if (typeName.equals("char")) { 151 sb.append("new Character(" + params[i].getName() + ")"); 152 } else if (typeName.equals("short")) { 153 sb.append("new Short(" + params[i].getName() + ")"); 154 } else if (typeName.equals("int")) { 155 sb.append("new Integer(" + params[i].getName() + ")"); 156 } else if (typeName.equals("float")) { 157 sb.append("new Float(" + params[i].getName() + ")"); 158 } else if (typeName.equals("double")) { 159 sb.append("new Double(" + params[i].getName() + ")"); 160 } else if (typeName.equals("long")) { 161 sb.append("new Long(" + params[i].getName() + ")"); 162 } else { 163 throw new RuntimeException ("Unexpected primitive parameter type"); 164 } 165 } else { 166 sb.append(params[i].getName()); 169 } 170 } 171 172 sb.append("}"); 173 String args = sb.toString(); 174 return args; 175 } 176 177 181 public static String buildTypeList(JMethod method) { 182 StringBuffer sb = new StringBuffer (); 183 sb.append("new Class[]{"); 184 185 JParameter[] params = method.getParameters(); 186 for (int i = 0; i < params.length; ++i) { 187 if (i > 0) { 188 sb.append(", "); 189 } 190 191 JType type = params[i].getType(); 192 String typeName = type.getQualifiedSourceName(); 193 sb.append(typeName); 194 sb.append(".class"); 195 } 196 197 sb.append("}"); 198 String classes = sb.toString(); 199 return classes; 200 } 201 202 public static int countNewlines(char[] buf, int start, int end) { 203 int total = 0; 204 while (start < end) { 205 switch (buf[start]) { 206 case '\r': 207 ++total; 208 if (start + 1 < end && buf[start + 1] == '\n') { 210 ++start; 211 } 212 break; 213 case '\n': 214 ++total; 215 break; 216 } 217 ++start; 218 } 219 return total; 220 } 221 222 public static int countNewlines(String src, int start, int end) { 223 return countNewlines(src.toCharArray(), start, end); 224 } 225 226 230 public static String escapeQuotesAndSlashes(String str) { 231 StringBuffer buf = new StringBuffer (str); 232 escapeQuotesAndSlashes(buf); 233 return buf.toString(); 234 } 235 236 public static Interval findJsniSource(JMethod method) 237 throws UnableToCompleteException { 238 assert (method.isNative()); 239 int bodyStart = method.getBodyStart(); 240 int bodyEnd = method.getBodyEnd(); 241 int bodyLen = bodyEnd - bodyStart + 1; 242 char[] source = method.getEnclosingType().getCompilationUnit().getSource(); 243 String js = String.valueOf(source, bodyStart, bodyLen); 244 245 int jsniStart = js.indexOf(JSNI_BLOCK_START); 246 if (jsniStart == -1) { 247 return null; 248 } 249 250 int jsniEnd = js.indexOf(JSNI_BLOCK_END, jsniStart); 251 if (jsniEnd == -1) { 252 return null; 255 } 256 257 int srcStart = bodyStart + jsniStart + JSNI_BLOCK_START.length(); 258 int srcEnd = bodyStart + jsniEnd; 259 return new Interval(srcStart, srcEnd); 260 } 261 262 269 public static String generateEscapedJavaScriptForHostedMode(JsNode node) { 270 String source = generateJavaScriptForHostedMode(node); 271 StringBuffer body = new StringBuffer (source.length()); 272 body.append(source); 273 escapeQuotesAndSlashes(body); 274 fixupLinebreaks(body); 275 return body.toString(); 276 } 277 278 282 public static String getJsniSignature(JMethod method) { 283 String name = method.getName(); 284 String className = method.getEnclosingType().getQualifiedSourceName(); 285 286 StringBuffer sb = new StringBuffer (); 287 sb.append(className); 288 sb.append("::"); 289 sb.append(name); 290 sb.append("("); 291 JParameter[] params = method.getParameters(); 292 for (int i = 0; i < params.length; ++i) { 293 JParameter param = params[i]; 294 String typeSig = param.getType().getJNISignature(); 295 sb.append(typeSig); 296 } 297 sb.append(")"); 298 String fullName = sb.toString(); 299 return fullName; 300 } 301 302 305 public static JsBlock parseAsFunctionBody(TreeLogger logger, String js, 306 String location, int startLine) throws UnableToCompleteException { 307 js = "function(){ " + js + " }"; 309 310 JsParser jsParser = new JsParser(); 311 JsProgram jsPgm = new JsProgram(); 312 StringReader r = new StringReader (js); 313 314 try { 315 JsStatements stmts = jsParser.parse(jsPgm.getScope(), r, startLine); 316 317 JsFunction fn = (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression(); 321 return fn.getBody(); 322 } catch (IOException e) { 323 logger.log(TreeLogger.ERROR, "Error reading JavaScript source", e); 324 throw new UnableToCompleteException(); 325 } catch (JsParserException e) { 326 SourceDetail dtl = e.getSourceDetail(); 327 if (dtl != null) { 328 StringBuffer sb = new StringBuffer (); 329 sb.append(location); 330 sb.append("("); 331 sb.append(dtl.getLine()); 332 sb.append(", "); 333 sb.append(dtl.getLineOffset()); 334 sb.append("): "); 335 sb.append(e.getMessage()); 336 logger.log(TreeLogger.ERROR, sb.toString(), e); 337 throw new UnableToCompleteException(); 338 } else { 339 logger.log(TreeLogger.ERROR, "Error parsing JSNI source", e); 340 throw new UnableToCompleteException(); 341 } 342 } 343 } 344 345 349 private static void escapeQuotesAndSlashes(StringBuffer buf) { 350 for (int i = 0; i < buf.length(); ++i) { 351 char c = buf.charAt(i); 352 if (c == '\"' || c == '\\') { 353 buf.insert(i, '\\'); 354 i += 1; 355 } 356 } 357 } 358 359 363 private static void fixupLinebreaks(StringBuffer body) { 364 for (int i = 0; i < body.length(); ++i) { 365 char c = body.charAt(i); 366 if (c == '\r') { 367 body.setCharAt(i, 'r'); 368 body.insert(i, '\\'); 369 i += 1; 370 } else if (c == '\n') { 371 body.setCharAt(i, 'n'); 372 body.insert(i, '\\'); 373 i += 1; 374 } 375 } 376 } 377 378 382 private static String generateJavaScriptForHostedMode(JsNode node) { 383 DefaultTextOutput out = new DefaultTextOutput(false); 384 JsSourceGenWithJsniIdentFixup vi = new JsSourceGenWithJsniIdentFixup(out); 385 vi.accept(node); 386 return out.toString(); 387 } 388 389 } 390 | Popular Tags |