diff options
author | Sven Gothel <[email protected]> | 2008-07-18 12:18:39 +0000 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2008-07-18 12:18:39 +0000 |
commit | c020a396e0cab63fa2b4d283decbea7d20ce3511 (patch) | |
tree | ff6b28bf17ed1739ca715ed443795af8f4fe2196 | |
parent | aa1a3b6381b79fa1caa43bd6169244f1cff23500 (diff) |
- New config feature: 'IgnoreExtendedInterfaceSymbols <java class source file>'
All enums and functions within the specified interface (or abstract class),
will not be emitted in the resulting interface.
This simplifies the GL profile config's a lot, as well reducing the footprint.
- Adding JavaParser 'com.sun.gluegen.jgram.JavaParser',
which collects enums and functions.
- New config feature 'UnsupportedExceptionType <exception name>',
which complements the 'RuntimeExceptionType <exception name>' feature.
UnsupportedExceptionType's are thrown in case a function is not available.
- Fix: BuildComposablePipeline
- Method names are now unique by:
- name, return type, modifiers and arguments
- Cleanup:
- mv: com.sun.gluegen.runtime.opengl.GLUnifiedName -> com.sun.gluegen.opengl.GLUnifiedName
- contains only the compile time portion of the former
- add: com.sun.gluegen.opengl.runtime.GLExtensionNames
- contains the extension name handling
- bulletproof GL function and GL enum recognition.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/gluegen/branches/JOGL_2_SANDBOX@101 a78bb65f-1512-4460-ba86-f6dc96a7bf27
17 files changed, 1945 insertions, 237 deletions
diff --git a/make/build.xml b/make/build.xml index 1ff74b8..dd9f147 100755 --- a/make/build.xml +++ b/make/build.xml @@ -81,11 +81,13 @@ <!-- The location of the GlueGen source and the C grammar files. --> <property name="gluegen" value="${src.java}/com/sun/gluegen" /> <property name="c.grammar" value="${gluegen}/cgram" /> + <property name="j.grammar" value="${gluegen}/jgram" /> <!-- The resulting location of the generated Java files from the - C grammar via ANTLR. --> <property name="gluegen.build" value="${src.generated.java}/com/sun/gluegen" /> - <property name="generated.java.from.grammar" value="${gluegen.build}/cgram" /> + <property name="generated.java.from.c.grammar" value="${gluegen.build}/cgram" /> + <property name="generated.java.from.j.grammar" value="${gluegen.build}/jgram" /> </target> <!-- @@ -95,7 +97,7 @@ - @param output.dir the directory to write the generated files to. If - the directory does not exist, it will be created. --> - <target name="generate.c.grammar"> + <target name="generate.grammar"> <!-- Generate the Java files --> <antlr target="${output.dir}/${target}" outputdirectory="${output.dir}"> <classpath refid="antlr.classpath" /> @@ -405,37 +407,47 @@ including supergrammars, in one place, so copy all of the grammars to the output directory up front so we don't put temporary files into the source tree --> - <mkdir dir="${generated.java.from.grammar}" /> - <copy todir="${generated.java.from.grammar}"> + <mkdir dir="${generated.java.from.c.grammar}" /> + <copy todir="${generated.java.from.c.grammar}"> <fileset dir="${c.grammar}"> <include name="*.g" /> </fileset> </copy> + <mkdir dir="${generated.java.from.j.grammar}" /> + <copy todir="${generated.java.from.j.grammar}"> + <fileset dir="${j.grammar}"> + <include name="*.g" /> + </fileset> + </copy> <!-- Generate the Java files from the C grammar using ANTLR. --> - <antcall target="generate.c.grammar"> - <param name="output.dir" value="${generated.java.from.grammar}" /> + <antcall target="generate.grammar"> + <param name="output.dir" value="${generated.java.from.c.grammar}" /> <param name="target" value="StdCParser.g" /> </antcall> <antcall target="generate.c.grammar.glib"> - <param name="output.dir" value="${generated.java.from.grammar}" /> + <param name="output.dir" value="${generated.java.from.c.grammar}" /> <param name="target" value="GnuCParser.g" /> <param name="glib" value="StdCParser.g" /> </antcall> - <antcall target="generate.c.grammar"> - <param name="output.dir" value="${generated.java.from.grammar}" /> + <antcall target="generate.grammar"> + <param name="output.dir" value="${generated.java.from.c.grammar}" /> <param name="target" value="GnuCTreeParser.g" /> </antcall> <antcall target="generate.c.grammar.glib"> - <param name="output.dir" value="${generated.java.from.grammar}" /> + <param name="output.dir" value="${generated.java.from.c.grammar}" /> <param name="target" value="GnuCEmitter.g" /> <param name="glib" value="GnuCTreeParser.g" /> </antcall> <antcall target="generate.c.grammar.glib"> - <param name="output.dir" value="${generated.java.from.grammar}" /> + <param name="output.dir" value="${generated.java.from.c.grammar}" /> <param name="target" value="HeaderParser.g" /> <param name="glib" value="GnuCTreeParser.g" /> </antcall> + <antcall target="generate.grammar"> + <param name="output.dir" value="${generated.java.from.j.grammar}" /> + <param name="target" value="JavaParser.g" /> + </antcall> <!-- Build GlueGen using the generated Java files along with the - original source. --> diff --git a/src/java/com/sun/gluegen/CMethodBindingEmitter.java b/src/java/com/sun/gluegen/CMethodBindingEmitter.java index 03b8422..2085477 100644 --- a/src/java/com/sun/gluegen/CMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/CMethodBindingEmitter.java @@ -133,7 +133,7 @@ public class CMethodBindingEmitter extends FunctionEmitter boolean forIndirectBufferAndArrayImplementation, MachineDescription machDesc) { - super(output); + super(output, false); assert(binding != null); assert(javaClassName != null); diff --git a/src/java/com/sun/gluegen/FunctionEmitter.java b/src/java/com/sun/gluegen/FunctionEmitter.java index 0d0f225..32ac071 100644 --- a/src/java/com/sun/gluegen/FunctionEmitter.java +++ b/src/java/com/sun/gluegen/FunctionEmitter.java @@ -47,6 +47,7 @@ public abstract class FunctionEmitter { public static final EmissionModifier STATIC = new EmissionModifier("static"); + private boolean isInterfaceVal; private ArrayList modifiers = new ArrayList(); private CommentEmitter commentEmitter = null; private PrintWriter defaultOutput; @@ -54,10 +55,11 @@ public abstract class FunctionEmitter /** * Constructs the FunctionEmitter with a CommentEmitter that emits nothing. */ - public FunctionEmitter(PrintWriter defaultOutput) + public FunctionEmitter(PrintWriter defaultOutput, boolean isInterface) { assert(defaultOutput != null); this.defaultOutput = defaultOutput; + this.isInterfaceVal = isInterface; } /** @@ -67,8 +69,11 @@ public abstract class FunctionEmitter modifiers = (ArrayList) arg.modifiers.clone(); commentEmitter = arg.commentEmitter; defaultOutput = arg.defaultOutput; + isInterfaceVal = arg.isInterfaceVal; } + public boolean isInterface() { return isInterfaceVal; } + public PrintWriter getDefaultOutput() { return defaultOutput; } public void addModifiers(Iterator/*<EmissionModifier>*/ mi) diff --git a/src/java/com/sun/gluegen/JavaConfiguration.java b/src/java/com/sun/gluegen/JavaConfiguration.java index 8cde267..a6ed790 100644 --- a/src/java/com/sun/gluegen/JavaConfiguration.java +++ b/src/java/com/sun/gluegen/JavaConfiguration.java @@ -44,6 +44,7 @@ import java.lang.reflect.Array; import java.util.*; import java.util.regex.*; +import com.sun.gluegen.jgram.*; import com.sun.gluegen.cgram.types.*; /** Parses and provides access to the contents of .cfg files for the @@ -100,6 +101,7 @@ public class JavaConfiguration { * checks fail. Defaults to RuntimeException. */ private String runtimeExceptionType = "RuntimeException"; + private String unsupportedExceptionType = "UnsupportedOperationException"; private Map/*<String,Integer>*/ accessControl = new HashMap(); private Map/*<String,TypeInfo>*/ typeInfoMap = new HashMap(); private Set/*<String>*/ returnsString = new HashSet(); @@ -109,6 +111,7 @@ public class JavaConfiguration { * converted to String args; value is List of Integer argument indices */ private Map/*<String,List<Integer>>*/ argumentsAreString = new HashMap(); + private Set/*<String>*/ ignoresIf = new HashSet(); private Set/*<Pattern>*/ ignores = new HashSet(); private Map/*<String,Pattern>*/ ignoreMap = new HashMap(); private Set/*<Pattern>*/ ignoreNots = new HashSet(); @@ -262,6 +265,8 @@ public class JavaConfiguration { public String gluegenRuntimePackage() { return gluegenRuntimePackage; } /** Returns the kind of exception to raise if run-time checks fail in the generated code. */ public String runtimeExceptionType() { return runtimeExceptionType; } + /** Returns the kind of exception to raise if run-time checks fail in the generated code. */ + public String unsupportedExceptionType() { return unsupportedExceptionType; } /** Returns the list of imports that should be emitted at the top of each .java file. */ public List/*<String>*/ imports() { return imports; } @@ -547,7 +552,11 @@ public class JavaConfiguration { } public void dumpIgnores() { - System.err.println("Ignores: "); + System.err.println("Ignores (If): "); + for (Iterator iter = ignoresIf.iterator(); iter.hasNext(); ) { + System.err.println("\t"+(String)iter.next()); + } + System.err.println("Ignores (All): "); for (Iterator iter = ignores.iterator(); iter.hasNext(); ) { System.err.println("\t"+(String)iter.next()); } @@ -555,13 +564,27 @@ public class JavaConfiguration { /** Returns true if this #define, function, struct, or field within a struct should be ignored during glue code generation. */ - public boolean shouldIgnore(String symbol) { + public boolean shouldIgnoreInInterface(String symbol) { + // Simple case; the entire symbol is in the interface ignore table. + if (ignoresIf.contains(symbol)) { + // System.err.println("Ignore If: "+symbol); + // dumpIgnores(); + return true; + } + return shouldIgnoreInImpl_Int(symbol); + } + + public boolean shouldIgnoreInImpl(String symbol) { + return shouldIgnoreInImpl_Int(symbol); + } + + private boolean shouldIgnoreInImpl_Int(String symbol) { // System.err.println("CHECKING IGNORE: " + symbol); // Simple case; the entire symbol is in the ignore table. if (ignores.contains(symbol)) { - // System.err.println("Ignore: "+symbol); + // System.err.println("Ignore Impl Simple: "+symbol); // dumpIgnores(); return true; } @@ -572,6 +595,7 @@ public class JavaConfiguration { Pattern regexp = (Pattern)iter.next(); Matcher matcher = regexp.matcher(symbol); if (matcher.matches()) { + // System.err.println("Ignore Impl RexEx: "+symbol); return true; } } @@ -586,8 +610,10 @@ public class JavaConfiguration { if (!matcher.matches()) { // Special case as this is most often likely to be the case. // Unignores are not used very often. - if(unignores.size() == 0) + if(unignores.size() == 0) { + // System.err.println("Ignore Impl unignores==0: "+symbol); return true; + } boolean unignoreFound = false; for (Iterator iter2 = unignores.iterator(); iter2.hasNext(); ) { @@ -600,6 +626,7 @@ public class JavaConfiguration { } if (!unignoreFound) + // System.err.println("Ignore Impl !unignore: "+symbol); return true; } } @@ -754,6 +781,8 @@ public class JavaConfiguration { // because ReturnedArrayLength changes them. } else if (cmd.equalsIgnoreCase("ArgumentIsString")) { readArgumentIsString(tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("IgnoreExtendedInterfaceSymbols")) { + readIgnoreExtendedInterfaceSymbols(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("Ignore")) { readIgnore(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("Unignore")) { @@ -816,6 +845,8 @@ public class JavaConfiguration { readRenameJavaMethod(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("RuntimeExceptionType")) { runtimeExceptionType = readString("RuntimeExceptionType", tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("UnsupportedExceptionType")) { + unsupportedExceptionType = readString("UnsupportedExceptionType", tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("JavaPrologue")) { readJavaPrologueOrEpilogue(tok, filename, lineNo, true); // Warning: make sure delimiters are reset at the top of this loop @@ -940,6 +971,41 @@ public class JavaConfiguration { } } + protected void readIgnoreExtendedInterfaceSymbols(StringTokenizer tok, String filename, int lineNo) { + File javaFile; + BufferedReader javaReader; + try { + javaFile = new File(tok.nextToken()); + javaReader = new BufferedReader(new FileReader(javaFile)); + } catch (FileNotFoundException e) { + System.err.println(e); + return; + } + + JavaLexer lexer = new JavaLexer(javaReader); + lexer.setFilename(javaFile.getName()); + + JavaParser parser = new JavaParser(lexer); + parser.setFilename(javaFile.getName()); + + try { + parser.compilationUnit(); + } catch (Exception e) { + System.err.println(e); + return; + } + + Set set = parser.getParsedEnumNames(); + for(Iterator iter = set.iterator(); iter.hasNext(); ) { + ignoresIf.add((String) iter.next()); + } + System.out.println("Functions"); + set = parser.getParsedFunctionNames(); + for(Iterator iter = set.iterator(); iter.hasNext(); ) { + ignoresIf.add((String) iter.next()); + } + } + protected void readIgnore(StringTokenizer tok, String filename, int lineNo) { try { String regex = tok.nextToken(); @@ -959,6 +1025,7 @@ public class JavaConfiguration { Pattern pattern = (Pattern) ignoreMap.get(regex); ignoreMap.remove(regex); ignores.remove(pattern); + ignoresIf.remove(pattern.toString()); // If the pattern wasn't registered before, then make sure we have a // valid pattern instance to put into the unignores set. diff --git a/src/java/com/sun/gluegen/JavaEmitter.java b/src/java/com/sun/gluegen/JavaEmitter.java index fa0c783..ac9644a 100644 --- a/src/java/com/sun/gluegen/JavaEmitter.java +++ b/src/java/com/sun/gluegen/JavaEmitter.java @@ -276,7 +276,7 @@ public class JavaEmitter implements GlueEmitter { // currently only emits only numeric defines -- if it handled #define'd // objects it would make a bigger difference. - if (!cfg.shouldIgnore(name)) { + if (!cfg.shouldIgnoreInInterface(name)) { String type = getJavaType(name, value); if (optionalComment != null && optionalComment.length() != 0) { javaWriter().println(" /** " + optionalComment + " */"); @@ -340,7 +340,7 @@ public class JavaEmitter implements GlueEmitter { for (Iterator iter = funcsToBind.iterator(); iter.hasNext(); ) { FunctionSymbol cFunc = (FunctionSymbol) iter.next(); // Check to see whether this function should be ignored - if (cfg.shouldIgnore(cFunc.getName())) { + if (cfg.shouldIgnoreInImpl(cFunc.getName())) { continue; // don't generate bindings for this symbol } @@ -352,12 +352,14 @@ public class JavaEmitter implements GlueEmitter { for (int i = 0; i < methodBindingEmitters.size(); ++i) { FunctionEmitter emitter = (FunctionEmitter)methodBindingEmitters.get(i); try { - emitter.emit(); + if (!emitter.isInterface() || !cfg.shouldIgnoreInInterface(emitter.getName())) { + emitter.emit(); + emitter.getDefaultOutput().println(); // put newline after method body + } } catch (Exception e) { throw new RuntimeException( "Error while emitting binding for \"" + emitter.getName() + "\"", e); } - emitter.getDefaultOutput().println(); // put newline after method body } // Return the list of FunctionSymbols that we generated gluecode for @@ -420,6 +422,7 @@ public class JavaEmitter implements GlueEmitter { new JavaMethodBindingEmitter(binding, writer, cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), !signatureOnly && needsBody, cfg.tagNativeBinding(), false, @@ -427,7 +430,8 @@ public class JavaEmitter implements GlueEmitter { false, false, false, - isUnimplemented); + isUnimplemented, + signatureOnly); switch (accessControl) { case ACC_PUBLIC: emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break; case ACC_PROTECTED: emitter.addModifier(JavaMethodBindingEmitter.PROTECTED); break; @@ -483,6 +487,7 @@ public class JavaEmitter implements GlueEmitter { new JavaMethodBindingEmitter(binding, writer, cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), false, cfg.tagNativeBinding(), true, @@ -490,6 +495,7 @@ public class JavaEmitter implements GlueEmitter { true, true, false, + false, false); emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); if (cfg.allStatic()) { @@ -508,6 +514,7 @@ public class JavaEmitter implements GlueEmitter { new JavaMethodBindingEmitter(binding, writer, cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), false, cfg.tagNativeBinding(), true, @@ -515,6 +522,7 @@ public class JavaEmitter implements GlueEmitter { true, false, true, + false, false); emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); @@ -752,7 +760,7 @@ public class JavaEmitter implements GlueEmitter { return; } - if (cfg.shouldIgnore(name)) { + if (cfg.shouldIgnoreInInterface(name)) { return; } @@ -916,7 +924,7 @@ public class JavaEmitter implements GlueEmitter { for (int i = 0; i < structType.getNumFields(); i++) { Field field = structType.getField(i); Type fieldType = field.getType(); - if (!cfg.shouldIgnore(name + " " + field.getName())) { + if (!cfg.shouldIgnoreInInterface(name + " " + field.getName())) { if (fieldType.isFunctionPointer()) { if (doBaseClass) { try { @@ -932,6 +940,7 @@ public class JavaEmitter implements GlueEmitter { new JavaMethodBindingEmitter(binding, writer, cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), true, cfg.tagNativeBinding(), false, @@ -939,6 +948,7 @@ public class JavaEmitter implements GlueEmitter { false, false, // FIXME: should unify this with the general emission code false, // FIXME: should unify this with the general emission code + false, // FIXME: should unify this with the general emission code false); emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); emitter.emit(); @@ -948,6 +958,7 @@ public class JavaEmitter implements GlueEmitter { new JavaMethodBindingEmitter(binding, writer, cfg.runtimeExceptionType(), + cfg.unsupportedExceptionType(), false, cfg.tagNativeBinding(), true, @@ -955,6 +966,7 @@ public class JavaEmitter implements GlueEmitter { true, true, // FIXME: should unify this with the general emission code false, // FIXME: should unify this with the general emission code + false, // FIXME: should unify this with the general emission code false); emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); emitter.addModifier(JavaMethodBindingEmitter.NATIVE); diff --git a/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java index 528a0cb..73b12d8 100644 --- a/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java @@ -65,6 +65,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter // Exception type raised in the generated code if runtime checks fail private String runtimeExceptionType; + private String unsupportedExceptionType; protected boolean emitBody; protected boolean eraseBufferAndArrayTypes; @@ -95,6 +96,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, + String unsupportedExceptionType, boolean emitBody, boolean tagNativeBinding, boolean eraseBufferAndArrayTypes, @@ -102,11 +104,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter boolean forImplementingMethodCall, boolean forDirectBufferImplementation, boolean forIndirectBufferAndArrayImplementation, - boolean isUnimplemented) + boolean isUnimplemented, + boolean isInterface) { - super(output); + super(output, isInterface); this.binding = binding; this.runtimeExceptionType = runtimeExceptionType; + this.unsupportedExceptionType = unsupportedExceptionType; this.emitBody = emitBody; this.tagNativeBinding = tagNativeBinding; this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes; @@ -126,6 +130,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter super(arg); binding = arg.binding; runtimeExceptionType = arg.runtimeExceptionType; + unsupportedExceptionType = arg.unsupportedExceptionType; emitBody = arg.emitBody; tagNativeBinding = arg.tagNativeBinding; eraseBufferAndArrayTypes = arg.eraseBufferAndArrayTypes; @@ -160,6 +165,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter return runtimeExceptionType; } + public String getUnsupportedExceptionType() { + return unsupportedExceptionType; + } + /** If the underlying function returns an array (currently only arrays of compound types are supported) as opposed to a pointer to an object, this method should be called to provide a @@ -377,7 +386,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter writer.println(); writer.println(" {"); if (isUnimplemented) { - writer.println(" throw new " + getRuntimeExceptionType() + "(\"Unimplemented\");"); + writer.println(" throw new " + getUnsupportedExceptionType() + "(\"Unimplemented\");"); } else { emitPrologueOrEpilogue(prologue, writer); emitPreCallSetup(binding, writer); diff --git a/src/java/com/sun/gluegen/jgram/JavaParser.g b/src/java/com/sun/gluegen/jgram/JavaParser.g new file mode 100644 index 0000000..e3a1962 --- /dev/null +++ b/src/java/com/sun/gluegen/jgram/JavaParser.g @@ -0,0 +1,1315 @@ +/* Java 1.3 Recognizer + * + * Run 'java Main [-showtree] directory-full-of-java-files' + * + * [The -showtree option pops up a Swing frame that shows + * the AST constructed from the parser.] + * + * Run 'java Main <directory full of java files>' + * + * Contributing authors: + * John Mitchell [email protected] + * Terence Parr [email protected] + * John Lilley [email protected] + * Scott Stanchfield [email protected] + * Markus Mohnen [email protected] + * Peter Williams [email protected] + * Allan Jacobs [email protected] + * Steve Messick [email protected] + * John Pybus [email protected] + * + * Version 1.00 December 9, 1997 -- initial release + * Version 1.01 December 10, 1997 + * fixed bug in octal def (0..7 not 0..8) + * Version 1.10 August 1998 (parrt) + * added tree construction + * fixed definition of WS,comments for mac,pc,unix newlines + * added unary plus + * Version 1.11 (Nov 20, 1998) + * Added "shutup" option to turn off last ambig warning. + * Fixed inner class def to allow named class defs as statements + * synchronized requires compound not simple statement + * add [] after builtInType DOT class in primaryExpression + * "const" is reserved but not valid..removed from modifiers + * Version 1.12 (Feb 2, 1999) + * Changed LITERAL_xxx to xxx in tree grammar. + * Updated java.g to use tokens {...} now for 2.6.0 (new feature). + * + * Version 1.13 (Apr 23, 1999) + * Didn't have (stat)? for else clause in tree parser. + * Didn't gen ASTs for interface extends. Updated tree parser too. + * Updated to 2.6.0. + * Version 1.14 (Jun 20, 1999) + * Allowed final/abstract on local classes. + * Removed local interfaces from methods + * Put instanceof precedence where it belongs...in relationalExpr + * It also had expr not type as arg; fixed it. + * Missing ! on SEMI in classBlock + * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus). + * fixed: didn't like Object[].class in parser or tree parser + * Version 1.15 (Jun 26, 1999) + * Screwed up rule with instanceof in it. :( Fixed. + * Tree parser didn't like (expr).something; fixed. + * Allowed multiple inheritance in tree grammar. oops. + * Version 1.16 (August 22, 1999) + * Extending an interface built a wacky tree: had extra EXTENDS. + * Tree grammar didn't allow multiple superinterfaces. + * Tree grammar didn't allow empty var initializer: {} + * Version 1.17 (October 12, 1999) + * ESC lexer rule allowed 399 max not 377 max. + * java.tree.g didn't handle the expression of synchronized + * statements. + * Version 1.18 (August 12, 2001) + * Terence updated to Java 2 Version 1.3 by + * observing/combining work of Allan Jacobs and Steve + * Messick. Handles 1.3 src. Summary: + * o primary didn't include boolean.class kind of thing + * o constructor calls parsed explicitly now: + * see explicitConstructorInvocation + * o add strictfp modifier + * o missing objBlock after new expression in tree grammar + * o merged local class definition alternatives, moved after declaration + * o fixed problem with ClassName.super.field + * o reordered some alternatives to make things more efficient + * o long and double constants were not differentiated from int/float + * o whitespace rule was inefficient: matched only one char + * o add an examples directory with some nasty 1.3 cases + * o made Main.java use buffered IO and a Reader for Unicode support + * o supports UNICODE? + * Using Unicode charVocabulay makes code file big, but only + * in the bitsets at the end. I need to make ANTLR generate + * unicode bitsets more efficiently. + * Version 1.19 (April 25, 2002) + * Terence added in nice fixes by John Pybus concerning floating + * constants and problems with super() calls. John did a nice + * reorg of the primary/postfix expression stuff to read better + * and makes f.g.super() parse properly (it was METHOD_CALL not + * a SUPER_CTOR_CALL). Also: + * + * o "finally" clause was a root...made it a child of "try" + * o Added stuff for asserts too for Java 1.4, but *commented out* + * as it is not backward compatible. + * + * Version 1.20 (October 27, 2002) + * + * Terence ended up reorging John Pybus' stuff to + * remove some nondeterminisms and some syntactic predicates. + * Note that the grammar is stricter now; e.g., this(...) must + * be the first statement. + * + * Trinary ?: operator wasn't working as array name: + * (isBig ? bigDigits : digits)[i]; + * + * Checked parser/tree parser on source for + * Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4, + * and the 110k-line jGuru server source. + * + * Version 1.21 (October 17, 2003) + * Fixed lots of problems including: + * Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g + * He found a problem/fix with floating point that start with 0 + * Ray also fixed problem that (int.class) was not recognized. + * Thorsten van Ellen noticed that \n are allowed incorrectly in strings. + * TJP fixed CHAR_LITERAL analogously. + * + * Version 1.22 (April 14, 2004) + * Changed vocab to be ..\uFFFE to avoid -1 char. removed dummy VOCAB rule. + * + * This grammar is in the PUBLIC DOMAIN + */ + +header { + package com.sun.gluegen.jgram; + + import java.util.*; + + import antlr.CommonAST; +} + +class JavaParser extends Parser; + +options { + k = 2; // two token lookahead + exportVocab=Java; // Call its vocabulary "Java" + codeGenMakeSwitchThreshold = 2; // Some optimizations + codeGenBitsetTestThreshold = 3; + defaultErrorHandler = false; // Don't generate parser error handlers + buildAST = true; + //buildAST = false; +} + +tokens { + BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF; + INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF; + PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE; + PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP; + POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT; + IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION; + FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract"; + STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL; +} + +{ + public void clearParsedEnumNames() { + enumNames.clear(); + } + + /** Returns the EnumTypes this HeaderParser processed. */ + public Set getParsedEnumNames() { + return enumNames; + } + + /** Clears the list of functions this HeaderParser has parsed. + Useful when reusing the same HeaderParser for more than one + header file. */ + public void clearParsedFunctionNames() { + functionNames.clear(); + } + + /** Returns the list of FunctionSymbols this HeaderParser has parsed. */ + public Set getParsedFunctionNames() { + return functionNames; + } + + private Set/*<String>*/ functionNames = new HashSet(); + // hash from name of an enumerated value to the EnumType to which it belongs + private Set/*<String>*/ enumNames = new HashSet(); + + private int blockDepth = 0; +} + +// Compilation Unit: In Java, this is a single file. This is the start +// rule for this parser +compilationUnit + : // A compilation unit starts with an optional package definition + ( packageDefinition + | /* nothing */ + ) + + // Next we have a series of zero or more import statements + ( importDefinition )* + + // Wrapping things up with any number of class or interface + // definitions + ( typeDefinition )* + + EOF! + ; + + +// Package statement: "package" followed by an identifier. +packageDefinition + options {defaultErrorHandler = true;} // let ANTLR handle errors + : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI! + ; + + +// Import statement: import followed by a package or class name +importDefinition + options {defaultErrorHandler = true;} + : i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI! + ; + +// A type definition in a file is either a class or interface definition. +typeDefinition + options {defaultErrorHandler = true;} + : m:modifiers! + ( classDefinition[#m] + | interfaceDefinition[#m] + ) + | SEMI! + ; + +/** A declaration is the creation of a reference or primitive-type variable + * Create a separate Type/Var tree for each var in the var list. + */ +declaration! + : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t] + {#declaration = #v;} + ; + +// A type specification is a type name with possible brackets afterwards +// (which would make it an array type). +typeSpec[boolean addImagNode] + : classTypeSpec[addImagNode] + | builtInTypeSpec[addImagNode] + ; + +// A class type specification is a class type with possible brackets afterwards +// (which would make it an array type). +classTypeSpec[boolean addImagNode] + : identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* + { + if ( addImagNode ) { + #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec); + } + } + ; + +// A builtin type specification is a builtin type with possible brackets +// afterwards (which would make it an array type). +builtInTypeSpec[boolean addImagNode] + : builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* + { + if ( addImagNode ) { + #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec); + } + } + ; + +// A type name. which is either a (possibly qualified) class name or +// a primitive (builtin) type +type + : identifier + | builtInType + ; + +// The primitive types. +builtInType + : "void" + | "boolean" + | "byte" + | "char" + | "short" + | "int" + | "float" + | "long" + | "double" + ; + +// A (possibly-qualified) java identifier. We start with the first IDENT +// and expand its name by adding dots and following IDENTS +identifier + : IDENT ( DOT^ IDENT )* + ; + +identifierStar + : IDENT + ( DOT^ IDENT )* + ( DOT^ STAR )? + ; + +// A list of zero or more modifiers. We could have used (modifier)* in +// place of a call to modifiers, but I thought it was a good idea to keep +// this rule separate so they can easily be collected in a Vector if +// someone so desires +modifiers + : ( modifier )* + {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);} + ; + +// modifiers for Java classes, interfaces, class/instance vars and methods +modifier + : "private" + | "public" + | "protected" + | "static" + | "transient" + | "final" + | "abstract" + | "native" + | "threadsafe" + | "synchronized" +// | "const" // reserved word, but not valid + | "volatile" + | "strictfp" + ; + +// Definition of a Java class +classDefinition![AST modifiers] + : "class" IDENT + // it _might_ have a superclass... + sc:superClassClause + // it might implement some interfaces... + ic:implementsClause + // now parse the body of the class + cb:classBlock + {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"], + modifiers,IDENT,sc,ic,cb);} + ; + +superClassClause! + : ( "extends" id:identifier )? + {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);} + ; + +// Definition of a Java Interface +interfaceDefinition![AST modifiers] + : "interface" IDENT + // it might extend some other interfaces + ie:interfaceExtends + // now parse the body of the interface (looks like a class...) + cb:classBlock + {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"], + modifiers,IDENT,ie,cb);} + ; + + +// This is the body of a class. You can have fields and extra semicolons, +// That's about it (until you see what a field is...) +classBlock + : LCURLY! { blockDepth++; } + ( field | SEMI! )* + RCURLY! { blockDepth--; } + {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);} + ; + +// An interface can extend several other interfaces... +interfaceExtends + : ( + e:"extends"! + identifier ( COMMA! identifier )* + )? + {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"], + #interfaceExtends);} + ; + +// A class can implement several interfaces... +implementsClause + : ( + i:"implements"! identifier ( COMMA! identifier )* + )? + {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"], + #implementsClause);} + ; + +// Now the various things that can be defined inside a class or interface... +// Note that not all of these are really valid in an interface (constructors, +// for example), and if this grammar were used for a compiler there would +// need to be some semantic checks to make sure we're doing the right thing... +field! + : // method, constructor, or variable declaration + mods:modifiers + ( h:ctorHead s:constructorBody // constructor + {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);} + + | cd:classDefinition[#mods] // inner class + {#field = #cd;} + + | id:interfaceDefinition[#mods] // inner interface + {#field = #id;} + + | t:typeSpec[false] // method or variable declaration(s) + ( fn:IDENT // the name of the method + + // parse the formal parameter declarations. + LPAREN! param:parameterDeclarationList RPAREN! + + rt:declaratorBrackets[#t] + + // get the list of exceptions that this method is + // declared to throw + (tc:throwsClause)? + + ( s2:compoundStatement | SEMI ) + {#field = #(#[METHOD_DEF,"METHOD_DEF"], + mods, + #(#[TYPE,"TYPE"],rt), + fn, + param, + tc, + s2); + if(blockDepth==1) { + functionNames.add(fn.getText()); } } + | v:variableDefinitions[#mods,#t] SEMI +// {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);} + {#field = #v;} + ) + ) + + // "static { ... }" class initializer + | "static" s3:compoundStatement + {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);} + + // "{ ... }" instance initializer + | s4:compoundStatement + {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);} + ; + +constructorBody + : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; } + ( options { greedy=true; } : explicitConstructorInvocation)? + (statement)* + RCURLY! { blockDepth--; } + ; + +/** Catch obvious constructor calls, but not the expr.super(...) calls */ +explicitConstructorInvocation + : "this"! lp1:LPAREN^ argList RPAREN! SEMI! + {#lp1.setType(CTOR_CALL);} + | "super"! lp2:LPAREN^ argList RPAREN! SEMI! + {#lp2.setType(SUPER_CTOR_CALL);} + ; + +variableDefinitions[AST mods, AST t] + : variableDeclarator[getASTFactory().dupTree(mods), + getASTFactory().dupTree(t)] + ( COMMA! + variableDeclarator[getASTFactory().dupTree(mods), + getASTFactory().dupTree(t)] + )* + ; + +/** Declaration of a variable. This can be a class/instance variable, + * or a local variable in a method + * It can also include possible initialization. + */ +variableDeclarator![AST mods, AST t] + : id:IDENT d:declaratorBrackets[t] v:varInitializer + {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v); + if(blockDepth==1) { + enumNames.add(id.getText()); + } + } + ; + +declaratorBrackets[AST typ] + : {#declaratorBrackets=typ;} + (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* + ; + +varInitializer + : ( ASSIGN^ initializer )? + ; + +// This is an initializer used to set up an array. +arrayInitializer + : lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; } + ( initializer + ( + // CONFLICT: does a COMMA after an initializer start a new + // initializer or start the option ',' at end? + // ANTLR generates proper code by matching + // the comma as soon as possible. + options { + warnWhenFollowAmbig = false; + } + : + COMMA! initializer + )* + (COMMA!)? + )? + RCURLY! { blockDepth--; } + ; + + +// The two "things" that can initialize an array element are an expression +// and another (nested) array initializer. +initializer + : expression + | arrayInitializer + ; + +// This is the header of a method. It includes the name and parameters +// for the method. +// This also watches for a list of exception classes in a "throws" clause. +ctorHead + : IDENT // the name of the method + + // parse the formal parameter declarations. + LPAREN! parameterDeclarationList RPAREN! + + // get the list of exceptions that this method is declared to throw + (throwsClause)? + ; + +// This is a list of exception classes that the method is declared to throw +throwsClause + : "throws"^ identifier ( COMMA! identifier )* + ; + + +// A list of formal parameters +parameterDeclarationList + : ( parameterDeclaration ( COMMA! parameterDeclaration )* )? + {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"], + #parameterDeclarationList);} + ; + +// A formal parameter. +parameterDeclaration! + : pm:parameterModifier t:typeSpec[false] id:IDENT + pd:declaratorBrackets[#t] + {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"], + pm, #([TYPE,"TYPE"],pd), id);} + ; + +parameterModifier + : (f:"final")? + {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);} + ; + +// Compound statement. This is used in many contexts: +// Inside a class definition prefixed with "static": +// it is a class initializer +// Inside a class definition without "static": +// it is an instance initializer +// As the body of a method +// As a completely indepdent braced block of code inside a method +// it starts a new scope for variable definitions + +compoundStatement + : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; } + // include the (possibly-empty) list of statements + (statement)* + RCURLY! { blockDepth--; } + ; + + +statement + // A list of statements in curly braces -- start a new scope! + : compoundStatement + + // declarations are ambiguous with "ID DOT" relative to expression + // statements. Must backtrack to be sure. Could use a semantic + // predicate to test symbol table to see what the type was coming + // up, but that's pretty hard without a symbol table ;) + | (declaration)=> declaration SEMI! + + // An expression statement. This could be a method call, + // assignment statement, or any other expression evaluated for + // side-effects. + | expression SEMI! + + // class definition + | m:modifiers! classDefinition[#m] + + // Attach a label to the front of a statement + | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement + + // If-else statement + | "if"^ LPAREN! expression RPAREN! statement + ( + // CONFLICT: the old "dangling-else" problem... + // ANTLR generates proper code matching + // as soon as possible. Hush warning. + options { + warnWhenFollowAmbig = false; + } + : + "else"! statement + )? + + // For statement + | "for"^ + LPAREN! + forInit SEMI! // initializer + forCond SEMI! // condition test + forIter // updater + RPAREN! + statement // statement to loop over + + // While statement + | "while"^ LPAREN! expression RPAREN! statement + + // do-while statement + | "do"^ statement "while"! LPAREN! expression RPAREN! SEMI! + + // get out of a loop (or switch) + | "break"^ (IDENT)? SEMI! + + // do next iteration of a loop + | "continue"^ (IDENT)? SEMI! + + // Return an expression + | "return"^ (expression)? SEMI! + + // switch/case statement + | "switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; } + ( casesGroup )* + RCURLY! { blockDepth--; } + + // exception try-catch block + | tryBlock + + // throw an exception + | "throw"^ expression SEMI! + + // synchronize a statement + | "synchronized"^ LPAREN! expression RPAREN! compoundStatement + + // asserts (uncomment if you want 1.4 compatibility) + // | "assert"^ expression ( COLON! expression )? SEMI! + + // empty statement + | s:SEMI {#s.setType(EMPTY_STAT);} + ; + +casesGroup + : ( // CONFLICT: to which case group do the statements bind? + // ANTLR generates proper code: it groups the + // many "case"/"default" labels together then + // follows them with the statements + options { + greedy = true; + } + : + aCase + )+ + caseSList + {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);} + ; + +aCase + : ("case"^ expression | "default") COLON! + ; + +caseSList + : (statement)* + {#caseSList = #(#[SLIST,"SLIST"],#caseSList);} + ; + +// The initializer for a for loop +forInit + // if it looks like a declaration, it is + : ( (declaration)=> declaration + // otherwise it could be an expression list... + | expressionList + )? + {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);} + ; + +forCond + : (expression)? + {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);} + ; + +forIter + : (expressionList)? + {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);} + ; + +// an exception handler try/catch block +tryBlock + : "try"^ compoundStatement + (handler)* + ( finallyClause )? + ; + +finallyClause + : "finally"^ compoundStatement + ; + +// an exception handler +handler + : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement + ; + + +// expressions +// Note that most of these expressions follow the pattern +// thisLevelExpression : +// nextHigherPrecedenceExpression +// (OPERATOR nextHigherPrecedenceExpression)* +// which is a standard recursive definition for a parsing an expression. +// The operators in java have the following precedences: +// lowest (13) = *= /= %= += -= <<= >>= >>>= &= ^= |= +// (12) ?: +// (11) || +// (10) && +// ( 9) | +// ( 8) ^ +// ( 7) & +// ( 6) == != +// ( 5) < <= > >= +// ( 4) << >> +// ( 3) +(binary) -(binary) +// ( 2) * / % +// ( 1) ++ -- +(unary) -(unary) ~ ! (type) +// [] () (method call) . (dot -- identifier qualification) +// new () (explicit parenthesis) +// +// the last two are not usually on a precedence chart; I put them in +// to point out that new has a higher precedence than '.', so you +// can validy use +// new Frame().show() +// +// Note that the above precedence levels map to the rules below... +// Once you have a precedence chart, writing the appropriate rules as below +// is usually very straightfoward + + + +// the mother of all expressions +expression + : assignmentExpression + {#expression = #(#[EXPR,"EXPR"],#expression);} + ; + + +// This is a list of expressions. +expressionList + : expression (COMMA! expression)* + {#expressionList = #(#[ELIST,"ELIST"], expressionList);} + ; + + +// assignment expression (level 13) +assignmentExpression + : conditionalExpression + ( ( ASSIGN^ + | PLUS_ASSIGN^ + | MINUS_ASSIGN^ + | STAR_ASSIGN^ + | DIV_ASSIGN^ + | MOD_ASSIGN^ + | SR_ASSIGN^ + | BSR_ASSIGN^ + | SL_ASSIGN^ + | BAND_ASSIGN^ + | BXOR_ASSIGN^ + | BOR_ASSIGN^ + ) + assignmentExpression + )? + ; + + +// conditional test (level 12) +conditionalExpression + : logicalOrExpression + ( QUESTION^ assignmentExpression COLON! conditionalExpression )? + ; + + +// logical or (||) (level 11) +logicalOrExpression + : logicalAndExpression (LOR^ logicalAndExpression)* + ; + + +// logical and (&&) (level 10) +logicalAndExpression + : inclusiveOrExpression (LAND^ inclusiveOrExpression)* + ; + + +// bitwise or non-short-circuiting or (|) (level 9) +inclusiveOrExpression + : exclusiveOrExpression (BOR^ exclusiveOrExpression)* + ; + + +// exclusive or (^) (level 8) +exclusiveOrExpression + : andExpression (BXOR^ andExpression)* + ; + + +// bitwise or non-short-circuiting and (&) (level 7) +andExpression + : equalityExpression (BAND^ equalityExpression)* + ; + + +// equality/inequality (==/!=) (level 6) +equalityExpression + : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)* + ; + + +// boolean relational expressions (level 5) +relationalExpression + : shiftExpression + ( ( ( LT^ + | GT^ + | LE^ + | GE^ + ) + shiftExpression + )* + | "instanceof"^ typeSpec[true] + ) + ; + + +// bit shift expressions (level 4) +shiftExpression + : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)* + ; + + +// binary addition/subtraction (level 3) +additiveExpression + : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)* + ; + + +// multiplication/division/modulo (level 2) +multiplicativeExpression + : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)* + ; + +unaryExpression + : INC^ unaryExpression + | DEC^ unaryExpression + | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression + | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression + | unaryExpressionNotPlusMinus + ; + +unaryExpressionNotPlusMinus + : BNOT^ unaryExpression + | LNOT^ unaryExpression + + // use predicate to skip cases like: (int.class) + | (LPAREN builtInTypeSpec[true] RPAREN) => + lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN! + unaryExpression + + // Have to backtrack to see if operator follows. If no operator + // follows, it's a typecast. No semantic checking needed to parse. + // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)" + | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=> + lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN! + unaryExpressionNotPlusMinus + + | postfixExpression + ; + +// qualified names, array expressions, method invocation, post inc/dec +postfixExpression + : + /* + "this"! lp1:LPAREN^ argList RPAREN! + {#lp1.setType(CTOR_CALL);} + + | "super"! lp2:LPAREN^ argList RPAREN! + {#lp2.setType(SUPER_CTOR_CALL);} + | + */ + primaryExpression + + ( + /* + options { + // the use of postfixExpression in SUPER_CTOR_CALL adds DOT + // to the lookahead set, and gives loads of false non-det + // warnings. + // shut them off. + generateAmbigWarnings=false; + } + : */ + DOT^ IDENT + ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} + argList + RPAREN! + )? + | DOT^ "this" + + | DOT^ "super" + ( // (new Outer()).super() (create enclosing instance) + lp3:LPAREN^ argList RPAREN! + {#lp3.setType(SUPER_CTOR_CALL);} + | DOT^ IDENT + ( lps:LPAREN^ {#lps.setType(METHOD_CALL);} + argList + RPAREN! + )? + ) + | DOT^ newExpression + | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK! + )* + + ( // possibly add on a post-increment or post-decrement. + // allows INC/DEC on too much, but semantics can check + in:INC^ {#in.setType(POST_INC);} + | de:DEC^ {#de.setType(POST_DEC);} + )? + ; + +// the basic element of an expression +primaryExpression + : identPrimary ( options {greedy=true;} : DOT^ "class" )? + | constant + | "true" + | "false" + | "null" + | newExpression + | "this" + | "super" + | LPAREN! assignmentExpression RPAREN! + // look for int.class and int[].class + | builtInType + ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )* + DOT^ "class" + ; + +/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class, + * and a.b.c.class refs. Also this(...) and super(...). Match + * this or super. + */ +identPrimary + : IDENT + ( + options { + // .ident could match here or in postfixExpression. + // We do want to match here. Turn off warning. + greedy=true; + } + : DOT^ IDENT + )* + ( + options { + // ARRAY_DECLARATOR here conflicts with INDEX_OP in + // postfixExpression on LBRACK RBRACK. + // We want to match [] here, so greedy. This overcomes + // limitation of linear approximate lookahead. + greedy=true; + } + : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! ) + | ( options {greedy=true;} : + lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK! + )+ + )? + ; + +/** object instantiation. + * Trees are built as illustrated by the following input/tree pairs: + * + * new T() + * + * new + * | + * T -- ELIST + * | + * arg1 -- arg2 -- .. -- argn + * + * new int[] + * + * new + * | + * int -- ARRAY_DECLARATOR + * + * new int[] {1,2} + * + * new + * | + * int -- ARRAY_DECLARATOR -- ARRAY_INIT + * | + * EXPR -- EXPR + * | | + * 1 2 + * + * new int[3] + * new + * | + * int -- ARRAY_DECLARATOR + * | + * EXPR + * | + * 3 + * + * new int[1][2] + * + * new + * | + * int -- ARRAY_DECLARATOR + * | + * ARRAY_DECLARATOR -- EXPR + * | | + * EXPR 1 + * | + * 2 + * + */ +newExpression + : "new"^ type + ( LPAREN! argList RPAREN! (classBlock)? + + //java 1.1 + // Note: This will allow bad constructs like + // new int[4][][3] {exp,exp}. + // There needs to be a semantic check here... + // to make sure: + // a) [ expr ] and [ ] are not mixed + // b) [ expr ] and an init are not used together + + | newArrayDeclarator (arrayInitializer)? + ) + ; + +argList + : ( expressionList + | /*nothing*/ + {#argList = #[ELIST,"ELIST"];} + ) + ; + +newArrayDeclarator + : ( + // CONFLICT: + // newExpression is a primaryExpression which can be + // followed by an array index reference. This is ok, + // as the generated code will stay in this loop as + // long as it sees an LBRACK (proper behavior) + options { + warnWhenFollowAmbig = false; + } + : + lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} + (expression)? + RBRACK! + )+ + ; + +constant + : NUM_INT + | CHAR_LITERAL + | STRING_LITERAL + | NUM_FLOAT + | NUM_LONG + | NUM_DOUBLE + ; + +//---------------------------------------------------------------------------- +// The Java scanner +//---------------------------------------------------------------------------- +class JavaLexer extends Lexer; + +options { + exportVocab=Java; // call the vocabulary "Java" + testLiterals=false; // don't automatically test for literals + k=4; // four characters of lookahead + charVocabulary='\u0003'..'\u7FFE'; + // without inlining some bitset tests, couldn't do unicode; + // I need to make ANTLR generate smaller bitsets; see + // bottom of JavaLexer.java + codeGenBitsetTestThreshold=20; +} + +// OPERATORS +QUESTION : '?' ; +LPAREN : '(' ; +RPAREN : ')' ; +LBRACK : '[' ; +RBRACK : ']' ; +LCURLY : '{' ; +RCURLY : '}' ; +COLON : ':' ; +COMMA : ',' ; +//DOT : '.' ; +ASSIGN : '=' ; +EQUAL : "==" ; +LNOT : '!' ; +BNOT : '~' ; +NOT_EQUAL : "!=" ; +DIV : '/' ; +DIV_ASSIGN : "/=" ; +PLUS : '+' ; +PLUS_ASSIGN : "+=" ; +INC : "++" ; +MINUS : '-' ; +MINUS_ASSIGN : "-=" ; +DEC : "--" ; +STAR : '*' ; +STAR_ASSIGN : "*=" ; +MOD : '%' ; +MOD_ASSIGN : "%=" ; +SR : ">>" ; +SR_ASSIGN : ">>=" ; +BSR : ">>>" ; +BSR_ASSIGN : ">>>=" ; +GE : ">=" ; +GT : ">" ; +SL : "<<" ; +SL_ASSIGN : "<<=" ; +LE : "<=" ; +LT : '<' ; +BXOR : '^' ; +BXOR_ASSIGN : "^=" ; +BOR : '|' ; +BOR_ASSIGN : "|=" ; +LOR : "||" ; +BAND : '&' ; +BAND_ASSIGN : "&=" ; +LAND : "&&" ; +SEMI : ';' ; + + +// Whitespace -- ignored +WS : ( ' ' + | '\t' + | '\f' + // handle newlines + | ( options {generateAmbigWarnings=false;} + : "\r\n" // Evil DOS + | '\r' // Macintosh + | '\n' // Unix (the right way) + ) + { newline(); } + )+ + { _ttype = Token.SKIP; } + ; + +// Single-line comments +SL_COMMENT + : "//" + (~('\n'|'\r'))* ('\n'|'\r'('\n')?)? + {$setType(Token.SKIP); newline();} + ; + +// multiple-line comments +ML_COMMENT + : "/*" + ( /* '\r' '\n' can be matched in one alternative or by matching + '\r' in one iteration and '\n' in another. I am trying to + handle any flavor of newline that comes in, but the language + that allows both "\r\n" and "\r" and "\n" to all be valid + newline is ambiguous. Consequently, the resulting grammar + must be ambiguous. I'm shutting this warning off. + */ + options { + generateAmbigWarnings=false; + } + : + { LA(2)!='/' }? '*' + | '\r' '\n' {newline();} + | '\r' {newline();} + | '\n' {newline();} + | ~('*'|'\n'|'\r') + )* + "*/" + {$setType(Token.SKIP);} + ; + + +// character literals +CHAR_LITERAL + : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\'' + ; + +// string literals +STRING_LITERAL + : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"' + ; + + +// escape sequence -- note that this is protected; it can only be called +// from another lexer rule -- it will not ever directly return a token to +// the parser +// There are various ambiguities hushed in this rule. The optional +// '0'...'9' digit matches should be matched here rather than letting +// them go back to STRING_LITERAL to be matched. ANTLR does the +// right thing by matching immediately; hence, it's ok to shut off +// the FOLLOW ambig warnings. +protected +ESC + : '\\' + ( 'n' + | 'r' + | 't' + | 'b' + | 'f' + | '"' + | '\'' + | '\\' + | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT + | '0'..'3' + ( + options { + warnWhenFollowAmbig = false; + } + : '0'..'7' + ( + options { + warnWhenFollowAmbig = false; + } + : '0'..'7' + )? + )? + | '4'..'7' + ( + options { + warnWhenFollowAmbig = false; + } + : '0'..'7' + )? + ) + ; + + +// hexadecimal digit (again, note it's protected!) +protected +HEX_DIGIT + : ('0'..'9'|'A'..'F'|'a'..'f') + ; + + +// an identifier. Note that testLiterals is set to true! This means +// that after we match the rule, we look in the literals table to see +// if it's a literal or really an identifer +IDENT + options {testLiterals=true;} + : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')* + ; + + +// a numeric literal +NUM_INT + {boolean isDecimal=false; Token t=null;} + : '.' {_ttype = DOT;} + ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})? + { + if (t != null && t.getText().toUpperCase().indexOf('F')>=0) { + _ttype = NUM_FLOAT; + } + else { + _ttype = NUM_DOUBLE; // assume double + } + } + )? + + | ( '0' {isDecimal = true;} // special case for just '0' + ( ('x'|'X') + ( // hex + // the 'e'|'E' and float suffix stuff look + // like hex digits, hence the (...)+ doesn't + // know when to stop: ambig. ANTLR resolves + // it correctly by matching immediately. It + // is therefor ok to hush warning. + options { + warnWhenFollowAmbig=false; + } + : HEX_DIGIT + )+ + + | //float or double with leading zero + (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+ + + | ('0'..'7')+ // octal + )? + | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal + ) + ( ('l'|'L') { _ttype = NUM_LONG; } + + // only check to see if it's a float if looks like decimal so far + | {isDecimal}? + ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})? + | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})? + | f4:FLOAT_SUFFIX {t=f4;} + ) + { + if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) { + _ttype = NUM_FLOAT; + } + else { + _ttype = NUM_DOUBLE; // assume double + } + } + )? + ; + + +// a couple protected methods to assist in matching floating point numbers +protected +EXPONENT + : ('e'|'E') ('+'|'-')? ('0'..'9')+ + ; + + +protected +FLOAT_SUFFIX + : 'f'|'F'|'d'|'D' + ; + diff --git a/src/java/com/sun/gluegen/jgram/Test.java b/src/java/com/sun/gluegen/jgram/Test.java new file mode 100644 index 0000000..996d645 --- /dev/null +++ b/src/java/com/sun/gluegen/jgram/Test.java @@ -0,0 +1,132 @@ +package com.sun.gluegen.jgram; + +import java.util.*; + +import java.io.*; +// import antlr.collections.AST; +import antlr.collections.impl.*; +import antlr.debug.misc.*; +import antlr.*; +// import java.awt.event.*; + +class Test { + + static boolean showTree = false; + public static void main(String[] args) { + // Use a try/catch block for parser exceptions + try { + // if we have at least one command-line argument + if (args.length > 0 ) { + System.err.println("Parsing..."); + + // for each directory/file specified on the command line + for(int i=0; i< args.length;i++) { + if ( args[i].equals("-showtree") ) { + showTree = true; + } + else { + doFile(new File(args[i])); // parse it + } + } } + else + System.err.println("Usage: java com.sun.gluegen.jgram.Test [-showtree] "+ + "<directory or file name>"); + } + catch(Exception e) { + System.err.println("exception: "+e); + e.printStackTrace(System.err); // so we can get stack trace + } + } + + + // This method decides what action to take based on the type of + // file we are looking at + public static void doFile(File f) + throws Exception { + // If this is a directory, walk each file/dir in that directory + if (f.isDirectory()) { + String files[] = f.list(); + for(int i=0; i < files.length; i++) + doFile(new File(f, files[i])); + } + + // otherwise, if this is a java file, parse it! + else if ((f.getName().length()>5) && + f.getName().substring(f.getName().length()-5).equals(".java")) { + System.err.println(" "+f.getAbsolutePath()); + // parseFile(f.getName(), new FileInputStream(f)); + parseFile(f.getName(), new BufferedReader(new FileReader(f))); + } + } + + // Here's where we do the real work... + public static void parseFile(String f, Reader r) + throws Exception { + try { + // Create a scanner that reads from the input stream passed to us + JavaLexer lexer = new JavaLexer(r); + lexer.setFilename(f); + + // Create a parser that reads from the scanner + JavaParser parser = new JavaParser(lexer); + parser.setFilename(f); + + // start parsing at the compilationUnit rule + parser.compilationUnit(); + + Set set = parser.getParsedEnumNames(); + System.out.println("Enums"); + for(Iterator iter = set.iterator(); iter.hasNext(); ) { + String s = (String) iter.next(); + System.out.println(s); + } + System.out.println("Functions"); + set = parser.getParsedFunctionNames(); + for(Iterator iter = set.iterator(); iter.hasNext(); ) { + String s = (String) iter.next(); + System.out.println(s); + } + + // do something with the tree + //doTreeAction(f, parser.getAST(), parser.getTokenNames()); + } + catch (Exception e) { + System.err.println("parser exception: "+e); + e.printStackTrace(); // so we can get stack trace + } + } + + /* + public static void doTreeAction(String f, AST t, String[] tokenNames) { + if ( t==null ) return; + if ( showTree ) { + ((CommonAST)t).setVerboseStringConversion(true, tokenNames); + ASTFactory factory = new ASTFactory(); + AST r = factory.create(0,"AST ROOT"); + r.setFirstChild(t); + final ASTFrame frame = new ASTFrame("Java AST", r); + frame.setVisible(true); + frame.addWindowListener( + new WindowAdapter() { + public void windowClosing (WindowEvent e) { + frame.setVisible(false); // hide the Frame + frame.dispose(); + System.exit(0); + } + } + ); + // System.out.println(t.toStringList()); + } + JavaTreeParser tparse = new JavaTreeParser(); + try { + tparse.compilationUnit(t); + // System.out.println("successful walk of result AST for "+f); + } + catch (RecognitionException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } + + } */ +} + diff --git a/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java b/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java index cc9175b..6c9f377 100644 --- a/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java +++ b/src/java/com/sun/gluegen/opengl/BuildComposablePipeline.java @@ -65,7 +65,7 @@ public class BuildComposablePipeline classToComposeAround = Class.forName(nameOfClassToComposeAround); } catch (Exception e) { throw new RuntimeException( - "Could not find class \"" + nameOfClassToComposeAround + "\"", e); + "Could not find class \"" + nameOfClassToComposeAround + "\"", e); } String outputDir = args[1]; @@ -80,7 +80,7 @@ public class BuildComposablePipeline catch (IOException e) { throw new RuntimeException( - "Error generating composable pipeline source files", e); + "Error generating composable pipeline source files", e); } } @@ -92,7 +92,7 @@ public class BuildComposablePipeline if (! classToComposeAround.isInterface()) { throw new IllegalArgumentException( - classToComposeAround.getName() + " is not an interface class"); + classToComposeAround.getName() + " is not an interface class"); } try { @@ -116,14 +116,59 @@ public class BuildComposablePipeline { String pDir = outputDirectory; String pInterface = classToComposeAround.getName(); - List/*<Method>*/ publicMethods = Arrays.asList(classToComposeAround.getMethods()); + List/*<Method>*/ publicMethodsRaw = Arrays.asList(classToComposeAround.getMethods()); + Set/*<Method>*/ publicMethodsPlain = new HashSet(); + for (Iterator iter=publicMethodsRaw.iterator(); iter.hasNext(); ) { + publicMethodsPlain.add(new PlainMethod((Method)iter.next())); } - (new DebugPipeline(pDir, pInterface)).emit(publicMethods); - (new TracePipeline(pDir, pInterface)).emit(publicMethods); + (new DebugPipeline(pDir, pInterface)).emit(publicMethodsPlain); + (new TracePipeline(pDir, pInterface)).emit(publicMethodsPlain); } //------------------------------------------------------- + protected class PlainMethod + { + Method m; + + public PlainMethod(Method m) { + this.m=m; + } + + public Method getWrappedMethod() { return m; } + + public boolean equals(Object obj) { + if(obj instanceof PlainMethod) { + PlainMethod b = (PlainMethod)obj; + boolean res = + m.getName().equals(b.m.getName()) && + m.getModifiers() == b.m.getModifiers() && + m.getReturnType().equals(b.m.getReturnType()) && + Arrays.equals( m.getParameterTypes() , b.m.getParameterTypes() ) ; + return res; + } + return false; + } + + public int hashCode() { + int hash = m.getName().hashCode() ^ m.getModifiers() ^ m.getReturnType().hashCode(); + Class[] args = m.getParameterTypes(); + for(int i=0; i<args.length; i++) { + hash ^= args[i].hashCode(); + } + return hash; + } + + public String toString() { + Class[] args = m.getParameterTypes(); + return m.toString() + + "\n\tname: " + m.getName() + + "\n\tmods: " + m.getModifiers() + + "\n\tretu: " + m.getReturnType() + + "\n\targs[" + args.length + "]: "+Arrays.toString(args); + } + } + /** * Emits a Java source file that represents one element of the composable * pipeline. @@ -148,20 +193,20 @@ public class BuildComposablePipeline int lastDot = baseInterfaceClassName.lastIndexOf('.'); if (lastDot == -1) { - // no package, class is at root level - this.baseName = baseInterfaceClassName; - this.basePackage = null; + // no package, class is at root level + this.baseName = baseInterfaceClassName; + this.basePackage = null; } else - { - this.baseName = baseInterfaceClassName.substring(lastDot+1); - this.basePackage = baseInterfaceClassName.substring(0, lastDot); + { + this.baseName = baseInterfaceClassName.substring(lastDot+1); + this.basePackage = baseInterfaceClassName.substring(0, lastDot); } this.outputDir = outputDir; } - public void emit(List/*<Method>*/ methodsToWrap) throws IOException + public void emit(Iterable/*<Method>*/ methodsToWrap) throws IOException { String pipelineClassName = getPipelineName(); this.file = new File(outputDir + File.separatorChar + pipelineClassName + ".java"); @@ -175,29 +220,29 @@ public class BuildComposablePipeline PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(file))); CodeGenUtils.emitJavaHeaders(output, - basePackage, - pipelineClassName, + basePackage, + pipelineClassName, "com.sun.gluegen.runtime", // FIXME: should make configurable - true, - new String[] { "java.io.*", "javax.media.opengl.*" }, - new String[] { "public" }, - new String[] { baseName }, - null, - new CodeGenUtils.EmissionCallback() { - public void emit(PrintWriter w) { emitClassDocComment(w); } - } - ); + true, + new String[] { "java.io.*", "javax.media.opengl.*" }, + new String[] { "public" }, + new String[] { baseName }, + null, + new CodeGenUtils.EmissionCallback() { + public void emit(PrintWriter w) { emitClassDocComment(w); } + } + ); preMethodEmissionHook(output); - + constructorHook(output); - for (int i = 0; i < methodsToWrap.size(); ++i) + for (Iterator iter=methodsToWrap.iterator(); iter.hasNext(); ) { - Method m = (Method)methodsToWrap.get(i); - emitMethodDocComment(output, m); - emitSignature(output, m); - emitBody(output, m); + Method m = ((PlainMethod)iter.next()).getWrappedMethod(); + emitMethodDocComment(output, m); + emitSignature(output, m); + emitBody(output, m); } postMethodEmissionHook(output); @@ -246,8 +291,8 @@ public class BuildComposablePipeline if (retType != Void.TYPE) { - output.print(JavaType.createForClass(retType).getName()); - output.print(" _res = "); + output.print(JavaType.createForClass(retType).getName()); + output.print(" _res = "); } output.print(getDownstreamObjectName()); output.print('.'); @@ -260,7 +305,7 @@ public class BuildComposablePipeline if (retType != Void.TYPE) { - output.println(" return _res;"); + output.println(" return _res;"); } output.println(" }"); @@ -271,25 +316,25 @@ public class BuildComposablePipeline StringBuffer buf = new StringBuffer(256); if (!includeArgNames && !includeArgTypes) { - throw new IllegalArgumentException( - "Cannot generate arglist without both arg types and arg names"); + throw new IllegalArgumentException( + "Cannot generate arglist without both arg types and arg names"); } Class[] argTypes = m.getParameterTypes(); for (int i = 0; i < argTypes.length; ++i) { - if (includeArgTypes) - { - buf.append(JavaType.createForClass(argTypes[i]).getName()); - buf.append(' '); - } - - if (includeArgNames) - { - buf.append("arg"); - buf.append(i); - } - if (i < argTypes.length-1) { buf.append(','); } + if (includeArgTypes) + { + buf.append(JavaType.createForClass(argTypes[i]).getName()); + buf.append(' '); + } + + if (includeArgNames) + { + buf.append("arg"); + buf.append(i); + } + if (i < argTypes.length-1) { buf.append(','); } } return buf.toString(); @@ -387,16 +432,16 @@ public class BuildComposablePipeline } output.println(" // Debug code to make sure the pipeline is working; leave commented out unless testing this class"); output.println(" //System.err.println(\"Checking for GL errors " + - "after call to \" + caller + \"()\");"); + "after call to \" + caller + \"()\");"); output.println(); output.println(" int err = " + - getDownstreamObjectName() + - ".glGetError();"); + getDownstreamObjectName() + + ".glGetError();"); output.println(" if (err == GL_NO_ERROR) { return; }"); output.println(); output.println(" StringBuffer buf = new StringBuffer("); output.println(" \"glGetError() returned the following error codes " + - "after a call to \" + caller + \"(): \");"); + "after a call to \" + caller + \"(): \");"); output.println(); output.println(" // Loop repeatedly to allow for distributed GL implementations,"); output.println(" // as detailed in the glGetError() specification"); @@ -415,8 +460,8 @@ public class BuildComposablePipeline output.println(" default: throw new InternalError(\"Unknown glGetError() return value: \" + err);"); output.println(" }"); output.println(" } while ((--recursionDepth >= 0) && (err = " + - getDownstreamObjectName() + - ".glGetError()) != GL_NO_ERROR);"); + getDownstreamObjectName() + + ".glGetError()) != GL_NO_ERROR);"); output.println(" throw new GLException(buf.toString());"); output.println(" }"); if (hasImmediateMode) { @@ -458,18 +503,18 @@ public class BuildComposablePipeline { if (m.getName().equals("glBegin")) { - output.println(" insideBeginEndPair = true;"); - output.println(" // NOTE: can't check glGetError(); it's not allowed inside glBegin/glEnd pair"); + output.println(" insideBeginEndPair = true;"); + output.println(" // NOTE: can't check glGetError(); it's not allowed inside glBegin/glEnd pair"); } else { - if (m.getName().equals("glEnd")) - { - output.println(" insideBeginEndPair = false;"); - } - - // calls to glGetError() are only allowed outside of glBegin/glEnd pairs - output.println(" checkGLGetError(\"" + m.getName() + "\");"); + if (m.getName().equals("glEnd")) + { + output.println(" insideBeginEndPair = false;"); + } + + // calls to glGetError() are only allowed outside of glBegin/glEnd pairs + output.println(" checkGLGetError(\"" + m.getName() + "\");"); } } diff --git a/src/java/com/sun/gluegen/opengl/GLConfiguration.java b/src/java/com/sun/gluegen/opengl/GLConfiguration.java index d9f35ba..1d2e08a 100755 --- a/src/java/com/sun/gluegen/opengl/GLConfiguration.java +++ b/src/java/com/sun/gluegen/opengl/GLConfiguration.java @@ -186,23 +186,35 @@ public class GLConfiguration extends ProcAddressConfiguration { } } - public boolean shouldIgnore(String symbol) { - return shouldIgnore(symbol, false); - } - - public boolean shouldIgnore(String symbol, boolean skipExtensionCheck) { - // Check ignored extensions based on our knowledge of the static GL info - if (!skipExtensionCheck && glInfo != null) { + protected boolean shouldIgnoreExtension(String symbol, boolean criteria) { + if (criteria && glInfo != null) { String extension = glInfo.getExtension(symbol); if (extension != null && ignoredExtensions.contains(extension)) { - // System.err.println("GL Ignore: "+symbol+" within extension "+extension); - // dumpIgnores(); - return true; + // System.err.println("GL Ignore: "+symbol+" within extension "+extension); + // Throwable t = new Throwable("XXX"); + // t.printStackTrace(); + // dumpIgnores(); + return true; } } + return false; + } + + public boolean shouldIgnoreInInterface(String symbol) { + return shouldIgnoreInInterface(symbol, true); + } + + public boolean shouldIgnoreInInterface(String symbol, boolean checkEXT) { + return shouldIgnoreExtension(symbol, checkEXT) || super.shouldIgnoreInInterface(symbol); + } + + public boolean shouldIgnoreInImpl(String symbol) { + return shouldIgnoreInImpl(symbol, true); + } - return super.shouldIgnore(symbol); + public boolean shouldIgnoreInImpl(String symbol, boolean checkEXT) { + return shouldIgnoreExtension(symbol, checkEXT) || super.shouldIgnoreInImpl(symbol); } /** shall the non unified (uniq) vendor extensions be dropped ? */ diff --git a/src/java/com/sun/gluegen/opengl/GLEmitter.java b/src/java/com/sun/gluegen/opengl/GLEmitter.java index 0dd4ebf..c5477a0 100644 --- a/src/java/com/sun/gluegen/opengl/GLEmitter.java +++ b/src/java/com/sun/gluegen/opengl/GLEmitter.java @@ -46,7 +46,7 @@ import com.sun.gluegen.*; import com.sun.gluegen.cgram.types.*; import com.sun.gluegen.procaddress.*; import com.sun.gluegen.runtime.*; -import com.sun.gluegen.runtime.opengl.GLUnifiedName; +import com.sun.gluegen.runtime.opengl.GLExtensionNames; /** * A subclass of ProcAddressEmitter with special OpenGL-specific @@ -139,8 +139,8 @@ public class GLEmitter extends ProcAddressEmitter public void normalizeVEN() { name.normalizeVEN(); } - public boolean shouldIgnore(GLConfiguration cfg) { - return GLEmitter.shouldIgnore(name, cfg); + public boolean shouldIgnoreInInterface(GLConfiguration cfg) { + return GLEmitter.shouldIgnoreInInterface(name, cfg); } protected GLUnifiedName name; @@ -150,10 +150,18 @@ public class GLEmitter extends ProcAddressEmitter protected String optionalComment; } - protected static boolean shouldIgnore(GLUnifiedName name, GLConfiguration cfg) { - boolean res = cfg.shouldIgnore(name.getUni(), false); + protected static boolean shouldIgnoreInInterface(GLUnifiedName name, GLConfiguration cfg) { + boolean res = cfg.shouldIgnoreInInterface(name.getUni(), name.isUnique()); for (Iterator iter = name.getOrig().iterator(); !res && iter.hasNext(); ) { - res = cfg.shouldIgnore((String)iter.next(), true); + res = cfg.shouldIgnoreInInterface((String)iter.next(), false); + } + return res; + } + + protected static boolean shouldIgnoreInImpl(GLUnifiedName name, GLConfiguration cfg) { + boolean res = cfg.shouldIgnoreInImpl(name.getUni(), name.isUnique()); + for (Iterator iter = name.getOrig().iterator(); !res && iter.hasNext(); ) { + res = cfg.shouldIgnoreInImpl((String)iter.next(), false); } return res; } @@ -203,7 +211,7 @@ public class GLEmitter extends ProcAddressEmitter while( deIter.hasNext() ) { DefineEntry de = (DefineEntry) deIter.next(); if(de.isExtensionVEN()) { - String extSuffix = GLUnifiedName.getExtensionSuffix(de.name.getUni()); + String extSuffix = GLExtensionNames.getExtensionSuffix(de.name.getUni(), false); DefineEntry deUni = (DefineEntry) de.clone(); deUni.normalizeVEN(); DefineEntry deExist = (DefineEntry) defineMap.get(deUni.name.getUni()); @@ -234,7 +242,7 @@ public class GLEmitter extends ProcAddressEmitter deIter = defineMap.values().iterator(); while( deIter.hasNext() ) { DefineEntry de = (DefineEntry) deIter.next(); - if (de.shouldIgnore((GLConfiguration)cfg)) { + if (de.shouldIgnoreInInterface((GLConfiguration)cfg)) { continue; } String comment = de.getOptCommentString(); @@ -350,7 +358,7 @@ public class GLEmitter extends ProcAddressEmitter FunctionSymbol fsOrig = (FunctionSymbol) iter.next(); origFuncNames.add(fsOrig.getName()); GLUnifiedName uniName = new GLUnifiedName(fsOrig.getName()); - if (GLEmitter.shouldIgnore(uniName, (GLConfiguration)cfg)) { + if (GLEmitter.shouldIgnoreInImpl(uniName, (GLConfiguration)cfg)) { iter.remove(); // remove ignored function } else { if( uniName.isExtensionARB() && @@ -386,11 +394,11 @@ public class GLEmitter extends ProcAddressEmitter GLUnifiedName uniName = new GLUnifiedName(fsOrig.getName()); if(uniName.isExtensionVEN()) { uniName.normalizeVEN(); - if (GLEmitter.shouldIgnore(uniName, (GLConfiguration)cfg)) { + if (GLEmitter.shouldIgnoreInImpl(uniName, (GLConfiguration)cfg)) { System.err.println("INFO: Ignored: Remove Function:"+ uniName); iter.remove(); // remove ignored function } else { - String extSuffix = GLUnifiedName.getExtensionSuffix(fsOrig.getName()); + String extSuffix = GLExtensionNames.getExtensionSuffix(fsOrig.getName(), true); FunctionSymbol fsUni = new FunctionSymbol(uniName.getUni(), fsOrig.getType()); if(funcsSet.contains(fsUni)) { GLUnifiedName uniNameMap = (GLUnifiedName) funcNameMap.get(uniName.getUni()); @@ -460,12 +468,12 @@ public class GLEmitter extends ProcAddressEmitter w.println(" * it was statically linked."); w.println(" */"); w.println(" public long getAddressFor(String functionNameUsr) {"); - w.println(" String functionNameBase = com.sun.gluegen.runtime.opengl.GLUnifiedName.normalizeVEN(com.sun.gluegen.runtime.opengl.GLUnifiedName.normalizeARB(functionNameUsr));"); + w.println(" String functionNameBase = com.sun.gluegen.runtime.opengl.GLExtensionNames.normalizeVEN(com.sun.gluegen.runtime.opengl.GLExtensionNames.normalizeARB(functionNameUsr, true), true);"); w.println(" String addressFieldNameBase = " + getProcAddressConfig().gluegenRuntimePackage() + ".ProcAddressHelper.PROCADDRESS_VAR_PREFIX + functionNameBase;"); w.println(" java.lang.reflect.Field addressField = null;"); - w.println(" int funcNamePermNum = com.sun.gluegen.runtime.opengl.GLUnifiedName.getNamePermutationNumber(functionNameBase);"); + w.println(" int funcNamePermNum = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutationNumber(functionNameBase);"); w.println(" for(int i = 0; null==addressField && i < funcNamePermNum; i++) {"); - w.println(" String addressFieldName = com.sun.gluegen.runtime.opengl.GLUnifiedName.getNamePermutation(addressFieldNameBase, i);"); + w.println(" String addressFieldName = com.sun.gluegen.runtime.opengl.GLExtensionNames.getFuncNamePermutation(addressFieldNameBase, i);"); w.println(" try {"); w.println(" addressField = getClass().getField(addressFieldName);"); w.println(" } catch (Exception e) { }"); diff --git a/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java index 3983916..581dff0 100755 --- a/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java @@ -44,7 +44,6 @@ import java.util.*; import com.sun.gluegen.*; import com.sun.gluegen.cgram.types.*; import com.sun.gluegen.procaddress.*; -import com.sun.gluegen.runtime.opengl.GLUnifiedName; /** A specialization of the proc address emitter which knows how to change argument names to take into account Vertex Buffer Object / diff --git a/src/java/com/sun/gluegen/runtime/opengl/GLUnifiedName.java b/src/java/com/sun/gluegen/opengl/GLUnifiedName.java index 02545dd..cf99b66 100644 --- a/src/java/com/sun/gluegen/runtime/opengl/GLUnifiedName.java +++ b/src/java/com/sun/gluegen/opengl/GLUnifiedName.java @@ -35,132 +35,32 @@ * */ -package com.sun.gluegen.runtime.opengl; +package com.sun.gluegen.opengl; import java.util.*; import com.sun.gluegen.runtime.*; +import com.sun.gluegen.runtime.opengl.GLExtensionNames; public class GLUnifiedName implements Cloneable { - //GL_XYZ : GL_XYZ, GL_XYZ_GL2, GL_XYZ_ARB, GL_XYZ_OES, GL_XYZ_OML - //GL_XYZ : GL_XYZ, GL_GL2_XYZ, GL_ARB_XYZ, GL_OES_XYZ, GL_OML_XYZ - // - // Pass-1 Unify ARB extensions with the same value - // Pass-2 Unify vendor extensions, - // if exist as an ARB extension with the same value. - // Pass-3 Emit - - public static final String[] extensionsARB = { "ARB", "GL2", "OES", "OML" }; - public static final String[] extensionsVEN = { "AMD", - "APPLE", - "ATI", - "EXT", - "HP", - "IBM", - "MESA", - "NV", - "SGI", - "SGIS", - "SGIX", - "SUN", - "WIN" - }; - - public static final int getExtensionIdx(String[] extensions, String str) { - for(int i = extensions.length - 1 ; i>=0 ; i--) { - if(str.endsWith(extensions[i])) { - return i; - } - } - return -1; - } - - public static final boolean isExtension(String[] extensions, String str) { - return getExtensionIdx(extensions, str)>=0; - } - - public static final String getExtensionSuffix(String str) { - int idx = getExtensionIdx(extensionsARB, str); - if(idx>=0) { - return extensionsARB[idx]; - } - idx = getExtensionIdx(extensionsVEN, str); - if(idx>=0) { - return extensionsVEN[idx]; - } - return null; - } - - public static final String normalize(String[] extensions, String str) { - boolean touched = false; - for(int i = extensions.length - 1 ; !touched && i>=0 ; i--) { - if(str.endsWith("_"+extensions[i])) { - // enums - str = str.substring(0, str.length()-1-extensions[i].length()); - touched=true; - } else if(str.endsWith(extensions[i])) { - // functions - str = str.substring(0, str.length()-extensions[i].length()); - touched=true; - } - } - return str; - } - public static final String normalizeARB(String str) { - return normalize(extensionsARB, str); - } - public static final boolean isExtensionARB(String str) { - return isExtension(extensionsARB, str); - } - public static final String normalizeVEN(String str) { - return normalize(extensionsVEN, str); - } - public static final boolean isExtensionVEN(String str) { - return isExtension(extensionsVEN, str); - } - - public static final int getNamePermutationNumber(String name) { - if(isExtensionARB(name) || isExtensionVEN(name)) { - // no name permutation, if it's already a known extension - return 1; - } - return 1 + extensionsARB.length + extensionsVEN.length; - } - - public static final String getNamePermutation(String name, int i) { - // identity - if(i==0) { - return name; - } - if(0>i || i>=(1+extensionsARB.length + extensionsVEN.length)) { - throw new RuntimeException("Index out of range [0.."+(1+extensionsARB.length+extensionsVEN.length-1)+"]: "+i); - } - // ARB - i-=1; - if(i<extensionsARB.length) { - return name+extensionsARB[i]; - } - // VEN - i-=extensionsARB.length; - return name+extensionsVEN[i]; - } - - /** - */ public GLUnifiedName(String name) { - this(name, normalizeARB(name)); - } - - protected GLUnifiedName(String orig, String uni) { + isGLFunc = GLExtensionNames.isGLFunction(name); + isGLEnum = GLExtensionNames.isGLEnumeration(name); + if(!isGLFunc && !isGLEnum) { + nameUni=name; + } else { + nameUni=GLExtensionNames.normalizeARB(name, isGLFunc); + } this.nameOrig=new ArrayList(); - this.nameOrig.add(orig); - this.nameUni=uni; + this.nameOrig.add(name); } - protected GLUnifiedName(List origs, String uni) { + protected GLUnifiedName(List origs, String uni, boolean isGLFunc, boolean isGLEnum) { this.nameOrig=new ArrayList(); this.nameOrig.addAll(origs); this.nameUni=uni; + this.isGLFunc=isGLFunc; + this.isGLEnum=isGLEnum; } public void resetUni() { @@ -177,22 +77,36 @@ public class GLUnifiedName implements Cloneable { } } + /** + * unique in case this name reflects only one + * original entry (no extension unification) + */ + public boolean isUnique() { + return nameOrig.size()==1; + } + public boolean isExtensionARB() { boolean res = false; - for (Iterator iter = nameOrig.iterator(); !res && iter.hasNext(); ) { - res = isExtensionARB((String)iter.next()); + if(isGLFunc||isGLEnum) { + for (Iterator iter = nameOrig.iterator(); !res && iter.hasNext(); ) { + res = GLExtensionNames.isExtensionARB((String)iter.next(), isGLFunc); + } } return res; } public void normalizeVEN() { - nameUni=normalizeVEN(nameUni); + if(isGLFunc||isGLEnum) { + nameUni=GLExtensionNames.normalizeVEN(nameUni, isGLFunc); + } } public boolean isExtensionVEN() { boolean res = false; - for (Iterator iter = nameOrig.iterator(); !res && iter.hasNext(); ) { - res = isExtensionVEN((String)iter.next()); + if(isGLFunc||isGLEnum) { + for (Iterator iter = nameOrig.iterator(); !res && iter.hasNext(); ) { + res = GLExtensionNames.isExtensionVEN((String)iter.next(), isGLFunc); + } } return res; } @@ -249,7 +163,7 @@ public class GLUnifiedName implements Cloneable { } public Object clone() { - return new GLUnifiedName(nameOrig, nameUni); + return new GLUnifiedName(nameOrig, nameUni, isGLFunc, isGLEnum); } public String getUni() { return nameUni; } @@ -258,5 +172,6 @@ public class GLUnifiedName implements Cloneable { private List nameOrig; private String nameUni; + private boolean isGLFunc, isGLEnum; } diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java index 98340a9..ea1feb6 100755 --- a/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java +++ b/src/java/com/sun/gluegen/procaddress/ProcAddressEmitter.java @@ -94,6 +94,10 @@ public class ProcAddressEmitter extends JavaEmitter return getConfig().runtimeExceptionType(); } + public String unsupportedExceptionType() { + return getConfig().unsupportedExceptionType(); + } + protected JavaConfiguration createConfig() { return new ProcAddressConfiguration(); } diff --git a/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java index 4b65d84..f6ae58e 100755 --- a/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java @@ -126,7 +126,7 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName(); writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";"); writer.println(" if (__addr_ == 0) {"); - writer.println(" throw new " + emitter.runtimeExceptionType() + "(\"Method \\\"" + binding.getName() + "\\\" not available\");"); + writer.println(" throw new " + emitter.unsupportedExceptionType() + "(\"Method \\\"" + binding.getName() + "\\\" not available\");"); writer.println(" }"); } } diff --git a/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java b/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java new file mode 100644 index 0000000..cc9233d --- /dev/null +++ b/src/java/com/sun/gluegen/runtime/opengl/GLExtensionNames.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package com.sun.gluegen.runtime.opengl; + +import java.util.*; +import com.sun.gluegen.runtime.*; + +public class GLExtensionNames { + //GL_XYZ : GL_XYZ, GL_XYZ_GL2, GL_XYZ_ARB, GL_XYZ_OES, GL_XYZ_OML + //GL_XYZ : GL_XYZ, GL_GL2_XYZ, GL_ARB_XYZ, GL_OES_XYZ, GL_OML_XYZ + // + // Pass-1 Unify ARB extensions with the same value + // Pass-2 Unify vendor extensions, + // if exist as an ARB extension with the same value. + // Pass-3 Emit + + public static final String[] extensionsARB = { "ARB", "GL2", "OES", "OML" }; + public static final String[] extensionsVEN = { "AMD", + "APPLE", + "ATI", + "EXT", + "HP", + "IBM", + "MESA", + "MESAX", + "NV", + "SGI", + "SGIS", + "SGIX", + "SUN", + "WIN" + }; + + + public static final boolean isGLFunction(String str) { + return str.startsWith("gl") || /* str.startsWith("glu") || str.startsWith("glX") || */ + str.startsWith("egl") || str.startsWith("wgl") || str.startsWith("agl") || + str.startsWith("cgl") ; + } + + public static final boolean isGLEnumeration(String str) { + return str.startsWith("GL_") || str.startsWith("GLU_") || str.startsWith("GLX_") || + str.startsWith("EGL_") || str.startsWith("WGL_") || str.startsWith("AGL_") || + str.startsWith("CGL_") ; + } + + public static final int getExtensionIdx(String[] extensions, String str, boolean isGLFunc) { + if(isGLFunc) { + for(int i = extensions.length - 1 ; i>=0 ; i--) { + if( str.endsWith(extensions[i]) ) { + return i; + } + } + } else { + for(int i = extensions.length - 1 ; i>=0 ; i--) { + if( str.endsWith("_"+extensions[i]) ) { + return i; + } + } + } + return -1; + } + + public static final boolean isExtension(String[] extensions, String str, boolean isGLFunc) { + return getExtensionIdx(extensions, str, isGLFunc)>=0; + } + + public static final String getExtensionSuffix(String str, boolean isGLFunc) { + int idx = getExtensionIdx(extensionsARB, str, isGLFunc); + if(idx>=0) { + return extensionsARB[idx]; + } + idx = getExtensionIdx(extensionsVEN, str, isGLFunc); + if(idx>=0) { + return extensionsVEN[idx]; + } + return null; + } + + public static final String normalize(String[] extensions, String str, boolean isGLFunc) { + boolean touched = false; + for(int i = extensions.length - 1 ; !touched && i>=0 ; i--) { + if(isGLFunc) { + if(str.endsWith(extensions[i])) { + // functions + str = str.substring(0, str.length()-extensions[i].length()); + touched=true; + } + } else { + if(str.endsWith("_"+extensions[i])) { + // enums + str = str.substring(0, str.length()-1-extensions[i].length()); + touched=true; + } + } + } + return str; + } + public static final String normalizeARB(String str, boolean isGLFunc) { + return normalize(extensionsARB, str, isGLFunc); + } + public static final boolean isExtensionARB(String str, boolean isGLFunc) { + return isExtension(extensionsARB, str, isGLFunc); + } + public static final String normalizeVEN(String str, boolean isGLFunc) { + return normalize(extensionsVEN, str, isGLFunc); + } + public static final boolean isExtensionVEN(String str, boolean isGLFunc) { + return isExtension(extensionsVEN, str, isGLFunc); + } + + public static final int getFuncNamePermutationNumber(String name) { + if(isExtensionARB(name, true) || isExtensionVEN(name, true)) { + // no name permutation, if it's already a known extension + return 1; + } + return 1 + extensionsARB.length + extensionsVEN.length; + } + + public static final String getFuncNamePermutation(String name, int i) { + // identity + if(i==0) { + return name; + } + if(0>i || i>=(1+extensionsARB.length + extensionsVEN.length)) { + throw new RuntimeException("Index out of range [0.."+(1+extensionsARB.length+extensionsVEN.length-1)+"]: "+i); + } + // ARB + i-=1; + if(i<extensionsARB.length) { + return name+extensionsARB[i]; + } + // VEN + i-=extensionsARB.length; + return name+extensionsVEN[i]; + } +} + diff --git a/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java b/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java index f8858d2..3f88261 100644 --- a/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java +++ b/src/java/com/sun/gluegen/runtime/opengl/GLProcAddressHelper.java @@ -75,9 +75,9 @@ public class GLProcAddressHelper extends ProcAddressHelper { "\" in class " + tableClass.getName(), e); } long newProcAddress = 0; - int funcNamePermNum = GLUnifiedName.getNamePermutationNumber(funcNameBase); + int funcNamePermNum = GLExtensionNames.getFuncNamePermutationNumber(funcNameBase); for(int j = 0; 0==newProcAddress && j < funcNamePermNum; j++) { - String funcName = GLUnifiedName.getNamePermutation(funcNameBase, j); + String funcName = GLExtensionNames.getFuncNamePermutation(funcNameBase, j); try { if (DEBUG) { dout.println(" try function lookup: " + funcName + " / " + funcNameBase); |