001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 IBM Corp.
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.lang.jeannie;
020:
021: import java.io.CharArrayWriter;
022: import java.io.File;
023: import java.io.PrintWriter;
024: import java.io.StringReader;
025: import java.io.StringWriter;
026: import java.lang.reflect.Field;
027: import java.lang.reflect.Method;
028: import java.util.ArrayList;
029: import java.util.Collections;
030: import java.util.HashMap;
031: import java.util.HashSet;
032: import java.util.List;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.regex.Pattern;
036:
037: import xtc.Constants;
038: import xtc.lang.CAnalyzer;
039: import xtc.lang.JavaEntities;
040: import xtc.lang.JavaTypeConverter;
041: import xtc.lang.JavaUnitTests;
042: import xtc.parser.Result;
043: import xtc.parser.SemanticValue;
044: import xtc.tree.GNode;
045: import xtc.tree.LineMarker;
046: import xtc.tree.Location;
047: import xtc.tree.Node;
048: import xtc.tree.Printer;
049: import xtc.tree.Visitor;
050: import xtc.type.AliasT;
051: import xtc.type.C;
052: import xtc.type.ClassOrInterfaceT;
053: import xtc.type.ErrorT;
054: import xtc.type.Language;
055: import xtc.type.NumberT;
056: import xtc.type.PointerT;
057: import xtc.type.SourcePrinter;
058: import xtc.type.Type;
059: import xtc.type.VoidT;
060: import xtc.type.WrappedT;
061: import xtc.util.Runtime;
062: import xtc.util.SymbolTable;
063:
064: /**
065: * Static helper routines related to JNI and Jeannie.
066: * This is a good place to put code that is useful for more than one visitor.
067: *
068: * @author Martin Hirzel
069: * @version $Revision: 1.21 $
070: */
071: public final class Utilities {
072: static class MiniVisitor_containsCToJavaTransition extends Visitor {
073: public final Boolean visit(final LineMarker m) {
074: final Node n = m.getNode();
075: return null == n ? Boolean.FALSE : (Boolean) dispatch(n);
076: }
077:
078: public final Boolean visit(final Node n) {
079: for (int i = 0; i < n.size(); i++)
080: if (n.get(i) instanceof Node)
081: if (((Boolean) dispatch(n.getNode(i)))
082: .booleanValue())
083: return Boolean.TRUE;
084: return Boolean.FALSE;
085: }
086:
087: public final Boolean visitJavaImports(final GNode n) {
088: return Boolean.valueOf(null != n);
089: }
090:
091: public final Boolean visitJavaInCBlock(final GNode n) {
092: return Boolean.valueOf(null != n);
093: }
094:
095: public final Boolean visitJavaInCExpression(final GNode n) {
096: return Boolean.valueOf(null != n);
097: }
098:
099: public final Boolean visitJavaInCStatement(final GNode n) {
100: return Boolean.valueOf(null != n);
101: }
102:
103: public final Boolean visitJavaThrows(final GNode n) {
104: return Boolean.valueOf(null != n && null != n.get(0));
105: }
106:
107: public final Boolean visitJavaType(final GNode n) {
108: return Boolean.valueOf(null != n);
109: }
110: }
111:
112: static class MiniVisitor_containsJavaToCTransition extends Visitor {
113: public final Boolean visit(final Node n) {
114: for (int i = 0; i < n.size(); i++)
115: if (n.get(i) instanceof Node)
116: if (((Boolean) dispatch(n.getNode(i)))
117: .booleanValue())
118: return Boolean.TRUE;
119: return Boolean.FALSE;
120: }
121:
122: public final Boolean visitCDeclarations(final GNode n) {
123: return Boolean.valueOf(null != n);
124: }
125:
126: public final Boolean visitCInJavaBlock(final GNode n) {
127: return Boolean.valueOf(null != n);
128: }
129:
130: public final Boolean visitCInJavaExpression(final GNode n) {
131: return Boolean.valueOf(null != n);
132: }
133: }
134:
135: static class MiniVisitor_findScopeBoundaries extends Visitor {
136: private final Map<String, Location> _ends = new HashMap<String, Location>();
137: private final Map<String, Location> _starts = new HashMap<String, Location>();
138: private final List<String> _willEnd = new ArrayList<String>();
139:
140: public final void visit(final Node n) {
141: if (n.hasLocation()) {
142: final Location loc = n.getLocation();
143: for (final String scope : _willEnd)
144: _ends.put(scope, loc);
145: _willEnd.clear();
146: if (n.hasProperty(Constants.SCOPE))
147: _starts.put(
148: (String) n.getProperty(Constants.SCOPE),
149: loc);
150: }
151: for (final Object o : n)
152: if (o instanceof Node)
153: dispatch((Node) o);
154: if (n.hasLocation() && n.hasProperty(Constants.SCOPE))
155: _willEnd.add((String) n.getProperty(Constants.SCOPE));
156: }
157: }
158:
159: static class MiniVisitor_getSimpleDeclarators extends Visitor {
160: public final Set<String> visit(final Node n) {
161: Set<String> result = Utilities.EMPTY_SET;
162: for (final Object o : n) {
163: if (o instanceof Node) {
164: final Set<String> childSet = Utilities
165: .stringSet(dispatch((Node) o));
166: if (!childSet.isEmpty()) {
167: if (result.isEmpty())
168: result = childSet;
169: else
170: result.addAll(childSet);
171: }
172: }
173: }
174: return result;
175: }
176:
177: public final Set<String> visitSimpleDeclarator(final GNode n) {
178: final Set<String> result = new HashSet<String>(1);
179: result.add(n.getString(0));
180: return result;
181: }
182: }
183:
184: static class MiniVisitor_getTopLevelDeclarations extends Visitor {
185: public final Set<String> visit(final Node n) {
186: Set<String> result = Utilities.EMPTY_SET;
187: for (final Object o : n) {
188: if (o instanceof Node) {
189: final Set<String> childSet = Utilities
190: .stringSet(dispatch((Node) o));
191: if (!childSet.isEmpty()) {
192: if (result.isEmpty())
193: result = childSet;
194: else
195: result.addAll(childSet);
196: }
197: }
198: }
199: return result;
200: }
201:
202: public final Set<String> visitClassDeclaration(final GNode n) {
203: final Set<String> result = new HashSet<String>(1);
204: result.add(n.getString(1));
205: return result;
206: }
207:
208: public final Set<String> visitInterfaceDeclaration(final GNode n) {
209: final Set<String> result = new HashSet<String>(1);
210: result.add(n.getString(1));
211: return result;
212: }
213: }
214:
215: private static final String[] JAVA_BASE_TYPES = { "boolean",
216: "byte", "char", "short", "int", "long", "float", "double" };
217:
218: public static final Set<String> EMPTY_SET = Collections.emptySet();
219:
220: private static final Set<String> STANDARD_JNI_TYPE_DEFS = new HashSet<String>();
221:
222: private static final Pattern AUTO_PATTERN = Pattern
223: .compile("\\bauto\\b");
224:
225: // private static C C = (new Analyzer.JeannieCAnalyzer(new Analyzer(UnitTests.newRuntime(), new SymbolTable(), null))).c();
226: private static C C = (new Analyzer.JeannieCAnalyzer(null)).c();
227:
228: public static C c() {
229: return C;
230: }
231:
232: /**
233: * Don't use this method gratuitously. Originally, I used this to serialize
234: * ASTs into strings, then concatenated the strings into more code, then
235: * reparsed the result to a larger AST. But that is not only slow, it is also
236: * brittle, since the same typedefs must be available during both parses.
237: * Chances are you can use the ast directly as a parameter to an AST factory
238: * generated by FactoryFactory.
239: */
240: public static String cAstToString(final Node ast) {
241: return JavaUnitTests.cAstToString(ast);
242: }
243:
244: public static boolean containsCToJavaTransition(final Node n) {
245: final MiniVisitor_containsCToJavaTransition v = new MiniVisitor_containsCToJavaTransition();
246: final Boolean result = (Boolean) v.dispatch(n);
247: return result.booleanValue();
248: }
249:
250: public static boolean containsJavaToCTransition(final GNode n) {
251: final MiniVisitor_containsJavaToCTransition v = new MiniVisitor_containsJavaToCTransition();
252: final Boolean result = (Boolean) v.dispatch(n);
253: return result.booleanValue();
254: }
255:
256: public static String copyDropAuto(final String string) {
257: return AUTO_PATTERN.matcher(string).replaceAll("").trim();
258: }
259:
260: public static Type cPtrToBaseType(final Type cPtrType) {
261: return ((PointerT) C.pointerize(cPtrType)).getType();
262: }
263:
264: public static GNode cStringToAst(final String production,
265: final String code) {
266: return cStringToAst(production, code, null);
267: }
268:
269: public static GNode cStringToAst(final String production,
270: final String code, final Set<String> typedefs) {
271: try {
272: final GNode result = JavaUnitTests.cStringToAst(production,
273: code, typedefs);
274: return JavaEntities.scrubLocations(result);
275: } catch (final Exception e) {
276: throw new Error(e);
277: }
278: }
279:
280: public static Type cStringToType(final String code) {
281: return cStringToType(code, EMPTY_SET);
282: }
283:
284: public static Type cStringToType(final String code,
285: final Set<String> typedefs) {
286: final GNode ast = cStringToAst("TypeName", code, typedefs);
287: final CAnalyzer cAnalyzer = new CAnalyzer(newRuntime());
288: try {
289: final Field field = CAnalyzer.class
290: .getDeclaredField("table");
291: field.setAccessible(true);
292: field.set(cAnalyzer, new SymbolTable());
293: } catch (final Exception e) {
294: throw new Error(e);
295: }
296: final Type result = cAnalyzer.visitTypeName(ast);
297: return result;
298: }
299:
300: public static GNode cTypeToAst(final Type type, final String id,
301: final String production) {
302: final String code;
303: if (null == id) {
304: assert "TypeName".equals(production);
305: code = cTypeToString(type);
306: } else {
307: assert "StructureDeclaration".equals(production)
308: || "Declaration".equals(production);
309: code = cTypeToString(type, id) + ";";
310: }
311: final GNode result = cStringToAst(production,
312: copyDropAuto(code), typedefs(type));
313: return result;
314: }
315:
316: public static Type cTypeToJavaType(final SymbolTable tab,
317: final Runtime runtime, final Node n, final Type cType) {
318: if (cType.isVoid())
319: return JavaEntities.nameToBaseType("void");
320: {
321: final Type c = Utilities.getJavaClassOrInterfaceT(cType);
322: if (JavaEntities.isWrappedClassT(c)
323: || JavaEntities.isWrappedInterfaceT(c))
324: return c;
325: }
326: for (final String s : Utilities.JAVA_BASE_TYPES) {
327: if (Utilities.hasTypedefName(cType, "j" + s))
328: return JavaEntities.nameToBaseType(s);
329: if (Utilities.hasTypedefName(cType, "j" + s + "Array"))
330: return JavaEntities.typeWithDimensions(JavaEntities
331: .nameToBaseType(s), 1);
332: }
333: if (Utilities.hasTypedefName(cType, "jsize"))
334: return JavaEntities.nameToBaseType("int");
335: if (Utilities.hasTypedefName(cType, "jclass"))
336: return JavaEntities.tClass(tab);
337: if (Utilities.hasTypedefName(cType, "jstring"))
338: return JavaEntities.tString(tab);
339: if (Utilities.hasTypedefName(cType, "jthrowable"))
340: return JavaEntities.tThrowable(tab);
341: if (Utilities.hasTypedefName(cType, "jobjectArray"))
342: return JavaEntities.typeWithDimensions(JavaEntities
343: .tObject(tab), 1);
344: if (Utilities.hasTypedefName(cType, "jobject"))
345: return JavaEntities.tObject(tab);
346: if (C.isIntegral(cType)) {
347: String tgt = "long";
348: final Type jInt = (Type) tab.root().lookup("jint");
349: if (null != jInt && jInt.equals(C.convert(jInt, cType)))
350: tgt = "int";
351: else if (null != n)
352: runtime.warning("converting C type '" + cType
353: + "' to Java type '" + tgt + "'", n);
354: return JavaEntities.nameToBaseType(tgt);
355: }
356: if (C.isArithmetic(cType) && !C.isIntegral(cType)) {
357: String tgt = "double";
358: final Type jFloat = (Type) tab.root().lookup("jfloat");
359: if (null != jFloat
360: && jFloat.equals(C.convert(jFloat, cType)))
361: tgt = "float";
362: if (null != n)
363: runtime.warning("converting C type '" + cType
364: + "' to Java type '" + tgt + "'", n);
365: return JavaEntities.nameToBaseType(tgt);
366: }
367: runtime.error("illegal C type '" + cType
368: + "' in Java expression", n);
369: return JavaEntities.nameToBaseType("int");
370: }
371:
372: public static String cTypeToString(final Type type) {
373: return cTypeToString(type, null);
374: }
375:
376: public static String cTypeToString(final Type type, final String id) {
377: final CharArrayWriter writer = new CharArrayWriter();
378: final Printer printer = new Printer(writer);
379: final SourcePrinter sourcePrinter = new SourcePrinter(printer);
380: if (null == id)
381: sourcePrinter.print(type);
382: else
383: sourcePrinter.print(type, id);
384: printer.flush();
385: return writer.toString();
386: }
387:
388: public static Type currentFunctionOrMethod(final SymbolTable tab) {
389: for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s
390: .getParent()) {
391: final String scopeName = s.getName();
392: if (SymbolTable.isInNameSpace(scopeName, "method"))
393: return JavaEntities.currentMethod(tab);
394: if (SymbolTable.isFunctionScopeName(scopeName)
395: || SymbolTable.isMacroScopeName(scopeName)) {
396: final String functionName = SymbolTable
397: .fromNameSpace(scopeName);
398: return (Type) s.getParent().lookupLocally(functionName);
399: }
400: }
401: return null;
402: }
403:
404: public static String debuggerAstToString(final GNode ast) {
405: final CharArrayWriter writer = new CharArrayWriter();
406: final DebuggerAstPrinter printer = new DebuggerAstPrinter(
407: new Printer(writer));
408: printer.dispatch(ast);
409: return writer.toString();
410: }
411:
412: private static class DebuggerSymbolMapperStub implements
413: DebuggerSymbolMapper {
414: public VariableRemapEntry lookUpVariableRemap(
415: final String variable, final String sourceFile,
416: final int sourceLineNumber) {
417: if (variable.equals("known"))
418: return new VariableRemapEntry(1, 1, 5, 5,
419: DebuggerExpression.TargetSourceLanguage.C,
420: "known", "pcEnv->_known");
421: return null;
422: }
423:
424: public SourceFileAndLine getCurrentSourceFileAndLine() {
425: return new SourceFileAndLine("foo", 123);
426: }
427: }
428:
429: public static DebuggerSymbolMapper debuggerNewSymbolMapper() {
430: return new DebuggerSymbolMapperStub();
431: }
432:
433: /**
434: * Parse the input as a debugger command, and analyze the resulting AST. If
435: * either the parse or the analysis fails, return a message String. If neither
436: * fails, return an AST Node. If the input contains an embedded expression,
437: * the language argument determines whether it is "C" or "Java". The analyzer
438: * annotates each node in the AST with the language for that node. It also
439: * looks up variables and annotates them with their remapping based on the
440: * current file and line number, where available.
441: */
442: public static Object debuggerParseAndAnalyze(final String language,
443: final String input, final DebuggerSymbolMapper mapper) {
444: final Object result;
445: {
446: Node ast = null;
447: String msg = null;
448: try {
449: ast = debuggerStringToAst(language, input);
450: final StringWriter stringWriter = new StringWriter();
451: final DebuggerAstAnalyzer ana = new DebuggerAstAnalyzer(
452: newRuntime(), mapper);
453: ana._runtime.setErrConsole(new Printer(stringWriter));
454: ana.dispatch(ast);
455: msg = stringWriter.toString();
456: } catch (final Exception e) {
457: msg = e.getMessage();
458: }
459: result = (null == msg || "".equals(msg)) ? ast : msg;
460: }
461: assert null != result;
462: if (result instanceof Node)
463: DebuggerAstAnalyzer
464: .assertAllNodesHaveLanguage((Node) result);
465: return result;
466: }
467:
468: public static GNode debuggerStringToAst(final String language,
469: final String input) throws Exception {
470: final DebuggerParser parser = new DebuggerParser(
471: new StringReader(input), "<input>", input.length());
472: final Result parseResult = "C".equals(language) ? parser
473: .pCCommand(0) : parser.pJavaCommand(0);
474: if (parseResult.hasValue()) {
475: final SemanticValue val = (SemanticValue) parseResult;
476: if (val.index != input.length())
477: parser.signal(parseResult.parseError());
478: final GNode ast = (GNode) val.value;
479: return (GNode) new AstSimplifier(language).dispatch(ast);
480: }
481: parser.signal(parseResult.parseError());
482: return null;
483: }
484:
485: public static void dumpLineMarkers(final Set<LineMarker> ms,
486: final int limit) {
487: System.err.print("dumpLineNumbers(" + limit + " / " + ms.size()
488: + ")");
489: int i = -1 == limit ? Integer.MAX_VALUE : limit;
490: for (final LineMarker m : ms) {
491: i--;
492: if (0 > i)
493: break;
494: System.err.print(" " + m.line + ":");
495: Node j;
496: for (j = m; null != j && j instanceof LineMarker; j = ((LineMarker) j)
497: .getNode())
498: ;
499: System.err.print(null == j ? "null" : j.getName());
500: }
501: System.err.println();
502: }
503:
504: public static Type getJavaClassOrInterfaceT(final Type t) {
505: Type i = t;
506: do {
507: if (JavaEntities.isWrappedClassT(i)
508: || JavaEntities.isWrappedInterfaceT(i))
509: return i;
510: if (!(i instanceof WrappedT))
511: return t;
512: i = ((WrappedT) i).getType();
513: } while (true);
514: }
515:
516: public static String getSimpleDeclarator(final GNode declNode) {
517: final Set<String> all = getSimpleDeclarators(declNode);
518: if (all.size() != 1)
519: return null;
520: return all.iterator().next();
521: }
522:
523: public static Set<String> getSimpleDeclarators(final GNode declNode) {
524: final Visitor v = new MiniVisitor_getSimpleDeclarators();
525: @SuppressWarnings("unchecked")
526: final Set<String> result = (Set<String>) v.dispatch(declNode);
527: return result;
528: }
529:
530: public static boolean hasTypedefName(final Type t, final String name) {
531: Type i = t;
532: while (i instanceof WrappedT) {
533: if (i instanceof AliasT) {
534: final String n = i.toAlias().getName();
535: if (n.equals(name))
536: return true;
537: }
538: i = ((WrappedT) i).getType();
539: }
540: return false;
541: }
542:
543: public static boolean isJavaEntity(final Type e) {
544: if (JavaEntities.isWrappedClassT(e)
545: || JavaEntities.isWrappedInterfaceT(e))
546: return true;
547: if (e.isMethod() || e.isPackage())
548: return true;
549: if (JavaEntities.isParameterT(e) || JavaEntities.isFieldT(e)
550: || JavaEntities.isLocalT(e))
551: return Language.JAVA == e.getLanguage();
552: return false;
553: }
554:
555: public static boolean isPtrChar(final Type t) {
556: final Type p = c().pointerize(t);
557: if (!p.isPointer())
558: return false;
559: final Type e = p.toPointer().getType().resolve();
560: return e.isNumber()
561: && NumberT.Kind.CHAR == e.toNumber().getKind();
562: }
563:
564: public static boolean isPtrTypedef(final Type t,
565: final String typedefName) {
566: final Type p = c().pointerize(t);
567: return p.isPointer()
568: && hasTypedefName(p.toPointer().getType(), typedefName);
569: }
570:
571: public static String javaAstToString(final Node ast) {
572: return JavaEntities.javaAstToString(ast);
573: }
574:
575: public static boolean javaIsStaticMethod(final GNode n) {
576: final Type type = (Type) n.getProperty(Constants.TYPE);
577: assert type.isMethod();
578: return type.hasAttribute(JavaEntities.nameToModifier("static"));
579: }
580:
581: public static boolean javaIsVoidMethod(final GNode n) {
582: final Type returnType = ((Type) n.getProperty(Constants.TYPE))
583: .toMethod().getResult();
584: return returnType.isVoid();
585: }
586:
587: public static String javaTypeToApiType(final Type type) {
588: return javaTypeToApiType(type, false, true);
589: }
590:
591: public static String javaTypeToApiType(final Type type,
592: final boolean upcase, final boolean arrays) {
593: if (type.isVoid())
594: return "Void";
595: if (JavaEntities.isGeneralLValueT(type))
596: return javaTypeToApiType(JavaEntities.dereference(type),
597: upcase, arrays);
598: final boolean isArray = type.isArray();
599: final Type elemType = isArray ? JavaEntities
600: .arrayElementType(type.toArray()) : null;
601: String result = "Object";
602: for (final String s : JAVA_BASE_TYPES) {
603: final Type jBaseType = JavaEntities.nameToBaseType(s);
604: if (arrays && isArray) {
605: if (JavaTypeConverter.isIdentical(elemType, jBaseType)) {
606: result = s + "Array";
607: break;
608: }
609: } else {
610: if (JavaTypeConverter.isIdentical(type, jBaseType)) {
611: result = s;
612: break;
613: }
614: }
615: }
616: return upcase ? upcaseFirstLetter(result) : result;
617: }
618:
619: public static Type javaTypeToCType(final SymbolTable tab,
620: final Runtime runtime, final Node n, final Type jType,
621: final boolean keepIfClassOrInterface) {
622: if (jType.isError())
623: return ErrorT.TYPE;
624: if (jType.isVoid())
625: return VoidT.TYPE;
626: assert JavaEntities.isGeneralRValueT(jType);
627: if (JavaEntities.isNullT(jType))
628: return C.typeInteger("0");
629: if (keepIfClassOrInterface)
630: if (JavaEntities.isWrappedClassT(jType)
631: || JavaEntities.isWrappedInterfaceT(jType))
632: return jType;
633: String cTypeName = null;
634: for (final String s : Utilities.JAVA_BASE_TYPES) {
635: final Type jBaseType = JavaEntities.nameToBaseType(s);
636: if (JavaTypeConverter.isIdentical(jType, jBaseType))
637: cTypeName = "j" + s;
638: else if (JavaTypeConverter.isIdentical(jType, JavaEntities
639: .typeWithDimensions(jBaseType, 1)))
640: cTypeName = "j" + s + "Array";
641: if (null != cTypeName)
642: break;
643: }
644: final List<File> paths = JavaEntities.classpath(runtime);
645: if (null == cTypeName
646: && JavaTypeConverter.isAssignable(tab, paths,
647: JavaEntities.tClass(tab), jType))
648: cTypeName = "jclass";
649: if (null == cTypeName
650: && JavaTypeConverter.isAssignable(tab, paths,
651: JavaEntities.tString(tab), jType))
652: cTypeName = "jstring";
653: if (null == cTypeName
654: && JavaTypeConverter.isAssignable(tab, paths,
655: JavaEntities.tThrowable(tab), jType))
656: cTypeName = "jthrowable";
657: if (null == cTypeName && jType.isArray()) {
658: assert JavaEntities.isReferenceT(JavaEntities
659: .arrayElementType(jType.toArray()));
660: cTypeName = "jobjectArray";
661: }
662: if (null == cTypeName) {
663: assert JavaEntities.isReferenceT(jType);
664: cTypeName = "jobject";
665: }
666: final Type cType = (Type) tab.root().lookup(cTypeName);
667: if (null != cType)
668: return cType;
669: runtime.error("C typedef for '" + cTypeName
670: + "' missing; did you forget to #include <jni.h>?", n);
671: return ErrorT.TYPE;
672: }
673:
674: public static String jeannieAstToString(final GNode ast,
675: final String language) {
676: final CharArrayWriter writer = new CharArrayWriter();
677: final JeanniePrinter printer = new JeanniePrinter(new Printer(
678: writer), language);
679: printer.dispatch(ast);
680: return writer.toString();
681: }
682:
683: public static GNode jeannieStringToAst(final String production,
684: final String language, final String code) {
685: try {
686: return jeannieStringToAst(production, language, code, true);
687: } catch (final Exception e) {
688: throw new Error(e);
689: }
690: }
691:
692: public static GNode jeannieStringToAst(final String production,
693: final String language, final String escaped,
694: final boolean simple) throws Exception {
695: final Class[] paramTypes = { Integer.TYPE };
696: final Method method = JeannieParser.class.getDeclaredMethod("p"
697: + production, paramTypes);
698: method.setAccessible(true);
699: final String string = JavaEntities.unicodeUnescape(escaped);
700: final JeannieParser parser = new JeannieParser(
701: new StringReader(string), "<input>", string.length());
702: final Object[] paramValues = { new Integer(0) };
703: final Result parseResult = (Result) method.invoke(parser,
704: paramValues);
705: if (parseResult.hasValue()) {
706: final SemanticValue val = (SemanticValue) parseResult;
707: if (val.index != string.length())
708: parser.signal(parseResult.parseError());
709: final GNode ast = (GNode) val.value;
710: if (simple)
711: return (GNode) new AstSimplifier(language)
712: .dispatch(ast);
713: return ast;
714: }
715: parser.signal(parseResult.parseError());
716: return null;
717: }
718:
719: /**
720: * Part of name of C function implementing Java method as expected by linker,
721: * see JNI Specification <a
722: * href="http://java.sun.com/docs/books/jni/html/design.html#9984">§11.3</a>.
723: */
724: public static String jniMangledName(final String name) {
725: final StringBuffer b = new StringBuffer(name.length());
726: for (int i = 0; i < name.length(); i++) {
727: final char c = name.charAt(i);
728: switch (c) {
729: case '.':
730: b.append('_');
731: break;
732: case '_':
733: b.append("_1");
734: break;
735: case ';':
736: b.append("_2");
737: break;
738: case '[':
739: b.append("_3");
740: break;
741: default:
742: if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
743: || '0' <= c && c <= '9') {
744: b.append(c);
745: } else {
746: final String hex = Integer.toHexString(c);
747: b.append("_0");
748: for (int j = 0; j < 4 - hex.length(); j++)
749: b.append('0');
750: b.append(hex);
751: }
752: }
753: }
754: return b.toString();
755: }
756:
757: public static String jniMangledName(final SymbolTable tab,
758: final Type type) {
759: if (type.isClass())
760: return jniMangledName(JavaEntities.qNameWithDollars(tab,
761: type.toClass()));
762: if (type.isInterface())
763: return jniMangledName(JavaEntities.qNameWithDollars(tab,
764: type.toInterface()));
765: assert type.isMethod();
766: final ClassOrInterfaceT declaringType = JavaEntities
767: .declaringType(tab, type);
768: final String declaringMangled = jniMangledName(tab,
769: declaringType);
770: final String nameMangled = jniMangledName(type.toMethod()
771: .getName());
772: final String md = JavaEntities.typeToDescriptor(tab, type);
773: final String ad = md.substring(1 + md.indexOf('('), md
774: .indexOf(')'));
775: if (0 == ad.length())
776: return declaringMangled + "_" + nameMangled;
777: return declaringMangled + "_" + nameMangled + "__"
778: + jniMangledName(ad);
779: }
780:
781: public static Runtime newRuntime() {
782: final Runtime runtime = new Runtime();
783: runtime.dir("in", Runtime.INPUT_DIRECTORY, true, "").setValue(
784: Runtime.INPUT_DIRECTORY, JavaUnitTests.TEMP_DIR);
785: runtime.bool("markAST", "optionMarkAST", true,
786: "Mark AST nodes with types.").setValue("optionMarkAST",
787: true);
788: runtime.bool("strict", "optionStrict", true,
789: "Enforce strict C99 compliance.").setValue(
790: "optionStrict", true);
791: runtime.bool("pedantic", "optionPedantic", false,
792: "Enforce strict C99 compliance.").setValue(
793: "optionPedantic", true);
794: runtime.word("jniCall", "jniCall", false,
795: "Calling conventions qualifier to C JNI functions.")
796: .setValue("jniCall", "");
797: runtime.initDefaultValues();
798: return runtime;
799: }
800:
801: static void printLocalVariableMap(final PrintWriter out,
802: final Node root, final SymbolTable tab,
803: final CodeGenerator.Substitutions cSubstitutions,
804: final CodeGenerator.Substitutions javaSubstitutions) {
805: final MiniVisitor_findScopeBoundaries boundaries = new MiniVisitor_findScopeBoundaries();
806: boundaries.dispatch(root);
807: out.println("LocalVariableMap:");
808: out
809: .println("# file startLine startCol endLine endCol lang srcId tgtId");
810: printLocalVariableMap_helper(out, tab, boundaries, "C",
811: cSubstitutions);
812: printLocalVariableMap_helper(out, tab, boundaries, "Java",
813: javaSubstitutions);
814: }
815:
816: static void printLocalVariableMap_helper(final PrintWriter out,
817: final SymbolTable tab,
818: final MiniVisitor_findScopeBoundaries boundaries,
819: final String language,
820: final CodeGenerator.Substitutions substitutions) {
821: for (final CodeGenerator.StringString ss : substitutions) {
822: final String scopeName = ss._s1;
823: Location start = null;
824: if (false) {
825: start = boundaries._starts.get(scopeName);
826: } else {
827: for (String s = scopeName; 0 < s.length(); s = xtc.util.Utilities
828: .getQualifier(s)) {
829: start = boundaries._starts.get(s);
830: if (null != start)
831: break;
832: }
833: }
834: assert null != start;
835: final Location end = boundaries._ends.get(scopeName);
836: assert null == end || end.file.equals(start.file);
837: final String srcId = ss._s2;
838: final String tgtId = substitutions.get(tab
839: .getScope(scopeName), srcId);
840: out.print(" " + start.file + " " + start.line + " "
841: + start.column);
842: if (null == end)
843: out.print(" - -");
844: else
845: out.print(" " + end.line + " " + end.column);
846: out.println(" " + language + " " + srcId + " " + tgtId);
847: }
848: }
849:
850: public static void printTopLevelDeclarations(final PrintWriter out,
851: final Node root) {
852: final Visitor v = new MiniVisitor_getTopLevelDeclarations();
853: out.print("TopLevelClassesOrInterfaces:");
854: for (final String s : JavaEntities.stringSet(v.dispatch(root)))
855: out.print(" " + s);
856: out.println();
857: }
858:
859: public static Type pureCType(final SymbolTable tab,
860: final Runtime runtime, final Type javaOrCType) {
861: if (isJavaEntity(javaOrCType))
862: return javaTypeToCType(tab, runtime, null, javaOrCType,
863: false);
864: if (javaOrCType.isAnnotated())
865: return pureCType(tab, runtime, javaOrCType.toAnnotated()
866: .getType());
867: return javaOrCType;
868: }
869:
870: public static String qualifiedIdentifierToString(final GNode n) {
871: final StringBuilder b = new StringBuilder();
872: for (int i = 0; i < n.size(); i++) {
873: if (0 < i)
874: b.append(Constants.QUALIFIER);
875: b.append(n.getString(i));
876: }
877: return b.toString();
878: }
879:
880: public static Type returnType(final Type functionOrMethod) {
881: if (functionOrMethod.isMethod())
882: return functionOrMethod.toMethod().getResult();
883: else
884: return functionOrMethod.resolve().toFunction().getResult();
885: }
886:
887: public static Set<String> standardJniTypeDefs() {
888: if (STANDARD_JNI_TYPE_DEFS.isEmpty()) {
889: for (final String s : JAVA_BASE_TYPES) {
890: STANDARD_JNI_TYPE_DEFS.add("j" + s);
891: STANDARD_JNI_TYPE_DEFS.add("j" + s + "Array");
892: }
893: final String[] a = { "JNIEnv", "jclass", "jfieldID",
894: "jmethodID", "jobject", "jstring" };
895: for (final String s : a)
896: STANDARD_JNI_TYPE_DEFS.add(s);
897: }
898: return STANDARD_JNI_TYPE_DEFS;
899: }
900:
901: @SuppressWarnings("unchecked")
902: public static Set<String> stringSet(final Object s) {
903: return (Set<String>) s;
904: }
905:
906: public static String stringSetToString(final Set<String> s) {
907: final StringBuilder result = new StringBuilder();
908: for (final String e : s) {
909: if (0 < result.length())
910: result.append(' ');
911: result.append(e);
912: }
913: return result.toString();
914: }
915:
916: public static Set<String> typedefs(Type r) {
917: final Set<String> result = new HashSet<String>();
918: while (true) {
919: if (r.isAlias())
920: result.add(r.toAlias().getName());
921: if (r instanceof WrappedT)
922: r = ((WrappedT) r).getType();
923: else if (r instanceof PointerT)
924: r = ((PointerT) r).getType();
925: else
926: break;
927: }
928: return result;
929: }
930:
931: public static String upcaseFirstLetter(final String s) {
932: final char[] chars = s.toCharArray();
933: chars[0] = Character.toUpperCase(chars[0]);
934: return new String(chars);
935: }
936:
937: private Utilities() {
938: assert false;
939: }
940: }
|