diff options
author | Sven Gothel <[email protected]> | 2015-04-01 15:51:04 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-04-01 15:51:04 +0200 |
commit | c6d5ee30e023d030697f14ae2c444ce7a5542e94 (patch) | |
tree | 0013fef29a228522b6791630385932d38a36a399 /src/java | |
parent | c156343fec33ceea7f238b9766a9f4985fb92687 (diff) |
Bug 1153 - GlueGen: Support [const] [native] expressions and conversion to java space, incl. [native] numbers
Rewrite ConstantDefinition:
Add sub-class CNumber:
- containing integer/float values and their original qualifiers
[long, double, unsigned]
- conversion to java number
ConstantDefinition:
- holds native expression
- optionally holds CNumber representing native expression,
if [only] a number
- can compute equivalent java expression
with result type (JavaExpr)
Add static native number reg-expression
for number detection and parsing.
Add static native number to CNumber conversion methods.
+++
Retrieve full LISP tree and convert to serialized expression
to be utilized for expressions used in enumerates.
Parse enumerates, allowing const native expressions:
- Utilize ConstantDefinition
either for definite CNumber or expression
- Simply add "+1" for new default values,
if previous is an expression
Diffstat (limited to 'src/java')
-rw-r--r-- | src/java/com/jogamp/gluegen/ConstantDefinition.java | 831 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/DebugEmitter.java | 2 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/GlueGen.java | 11 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaEmitter.java | 279 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java | 2 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/TNode.java | 83 | ||||
-rw-r--r-- | src/java/com/jogamp/gluegen/cgram/types/EnumType.java | 76 |
7 files changed, 942 insertions, 342 deletions
diff --git a/src/java/com/jogamp/gluegen/ConstantDefinition.java b/src/java/com/jogamp/gluegen/ConstantDefinition.java index f8f4973..675c6d7 100644 --- a/src/java/com/jogamp/gluegen/ConstantDefinition.java +++ b/src/java/com/jogamp/gluegen/ConstantDefinition.java @@ -1,38 +1,35 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. +/** + * Copyright 2015 JogAmp Community. 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 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. + * 1. Redistributions 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. + * 2. Redistributions 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. + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ - package com.jogamp.gluegen; +import java.math.BigInteger; +import java.util.Map; +import java.util.regex.Matcher; import java.util.regex.Pattern; import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider; @@ -40,55 +37,351 @@ import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl; import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; -/** Represents the definition of a constant which was provided either - via a #define statement or through an enum definition. */ +/** + * Represents a [native] constant expression, + * comprises the [native] expression, see {@link #getNativeExpr()} + * and the optional {@link CNumber} representation, see {@link #getNumber()}. + * <p> + * The representation of the equivalent java expression including + * the result type is covered by {@link JavaExpr}, + * which can be computed via {@link #computeJavaExpr(Map)}. + * </p> + * <p> + * This class and its sub-classes define and convert all native expressions + * to Java space. + * </p> + */ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSemanticSymbol, ASTLocusTagProvider { + public static final long UNSIGNED_INT_MAX_VALUE = 0xffffffffL; + public static final BigInteger UNSIGNED_LONG_MAX_VALUE = new BigInteger("ffffffffffffffff", 16); + + /** + * A Number, either integer, optionally [long, unsigned], + * or floating point, optionally [double]. + */ + public static class CNumber { + /** + * {@code true} if number is integer and value stored in {@link #i}, + * otherwise {@code false} for floating point and value stored in {@link #f}. + */ + public final boolean isInteger; + /** {@code true} if number is a {@code long} {@link #isInteger}. */ + public final boolean isLong; + /** {@code true} if number is an {@code unsigned} {@link #isInteger}. */ + public final boolean isUnsigned; + /** The value if {@link #isInteger} */ + public final long i; + + /** {@code true} if number is a {@code double precision} {@code floating point}, i.e. !{@link #isInteger}. */ + public final boolean isDouble; + /** The value if !{@link #isInteger} */ + public final double f; + + /** ctor for integer number */ + public CNumber(final boolean isLong, final boolean isUnsigned, final long value) { + this.isInteger = true; + this.isLong = isLong; + this.isUnsigned = isUnsigned; + this.i = value; + this.isDouble = false; + this.f = 0.0; + } + /** ctor for floating point number */ + public CNumber(final boolean isDouble, final double value) { + this.isInteger = false; + this.isLong = false; + this.isUnsigned = false; + this.i = 0; + this.isDouble = isDouble; + this.f = value; + } + @Override + public int hashCode() { + return isInteger ? Long.valueOf(i).hashCode() : Double.valueOf(f).hashCode(); + } + @Override + public boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof CNumber) ) { + return false; + } + final CNumber t = (CNumber) arg; + return isInteger == t.isInteger && + ( isInteger ? i == t.i : f == t.f ); + } + public final String toJavaString() { + if( isInteger ) { + if( i >= 0 || isUnsigned ) { + if( isLong ) { + return "0x"+Long.toHexString(i)+"L"; + } else { + return "0x"+Integer.toHexString((int)i); + } + } else { + if( isLong ) { + return String.valueOf(i)+"L"; + } else { + return String.valueOf((int)i); + } + } + } else { + return String.valueOf(f) + ( !isDouble ? "f" : ""); + } + } + public final String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("["); + if( isInteger ) { + if( isUnsigned ) { + sb.append("unsigned "); + } + if( isLong) { + sb.append("long: "); + } else { + sb.append("int: "); + } + sb.append(i); + } else { + if( isDouble ) { + sb.append("double: "); + } else { + sb.append("float: "); + } + sb.append(f); + } + sb.append("]"); + return sb.toString(); + } + } + + /** + * A valid java expression, including its result type, + * usually generated from a native [C] expression, + * see {@link JavaExpr#create(ConstantDefinition)}. + */ + public static class JavaExpr { + public final String javaExpression; + public final CNumber resultType; + public final Number resultJavaType; + public final String resultJavaTypeName; + public JavaExpr(final String javaExpression, final CNumber resultType) { + this.javaExpression = javaExpression; + this.resultType = resultType; + if( resultType.isDouble ) { + resultJavaTypeName = "double"; + resultJavaType = Double.valueOf(resultType.f); + } else if( !resultType.isInteger ) { + resultJavaTypeName = "float"; + resultJavaType = Double.valueOf(resultType.f).floatValue(); + } else if( resultType.isLong ) { + resultJavaTypeName = "long"; + resultJavaType = Long.valueOf(resultType.i); + } else /* if( resultType.isInteger ) */ { + resultJavaTypeName = "int"; + resultJavaType = Long.valueOf(resultType.i).intValue(); + } + } + /** + * Computes a valid {@link JavaExpr java expression} based on the given {@link ConstantDefinition}, + * which may either be a single {@link CNumber}, see {@link ConstantDefinition#getNumber()}, + * or represents a native expression, see {@link ConstantDefinition#getExpr()}. + */ + public static JavaExpr compute(final ConstantDefinition constDef, + final Map<String, ConstantDefinition.JavaExpr> constMap) { + final boolean debug = GlueGen.debug(); + if( debug ) { + System.err.println("ConstJavaExpr.create: "+constDef); + } + if( constDef.hasNumber() ) { + // Already parsed as CNumber completely! + if( debug ) { + System.err.printf("V %s (isCNumber)%n", constDef); + } + return new JavaExpr(constDef.getNumber().toJavaString(), constDef.getNumber()); + } + final StringBuilder javaExpr = new StringBuilder(); + final String nativeExpr = constDef.getNativeExpr(); + + // "calculates" the result type of a simple expression + // example: (2+3)-(2.0f-3.0) -> Double + // example: (1 << 2) -> Integer + CNumber resultType = null; + final Matcher matcher = patternCPPOperand.matcher(nativeExpr); + int preStartIdx = 0; + int opEndIdx = 0; + while ( matcher.find() ) { + final int opStartIdx = matcher.start(); + if( opStartIdx > preStartIdx ) { + final String sValue = nativeExpr.substring(preStartIdx, opStartIdx).trim(); + if( sValue.length() > 0 ) { + if( debug ) { + System.err.printf("V %03d-%03d: %s%n", preStartIdx, opStartIdx, sValue); + } + resultType = processValue(constDef, sValue, constMap, resultType, javaExpr); + javaExpr.append(" "); + } + } + opEndIdx = matcher.end(); + final String op = nativeExpr.substring(opStartIdx, opEndIdx); + if( debug ) { + System.err.printf("O %03d-%03d: %s%n", opStartIdx, opEndIdx, op); + } + javaExpr.append(op).append(" "); + preStartIdx = opEndIdx; + } + if( opEndIdx < nativeExpr.length() ) { + // tail .. + final String sValue = nativeExpr.substring(opEndIdx).trim(); + if( sValue.length() > 0 ) { + if( debug ) { + System.err.printf("V %03d %03d-%03d: %s (tail)%n", preStartIdx, opEndIdx, nativeExpr.length(), sValue); + } + resultType = processValue(constDef, sValue, constMap, resultType, javaExpr); + } + } + final String javaExprS = javaExpr.toString().trim(); + if( null == resultType ) { + throw new GlueGenException("Cannot emit const \""+constDef.getName()+"\": value \""+nativeExpr+ + "\", parsed \""+javaExprS+"\" does not contain a constant number", constDef.getASTLocusTag()); + } + return new JavaExpr(javaExprS, resultType); + } + private static CNumber processValue(final ConstantDefinition constDef, + final String sValue, + final Map<String, ConstantDefinition.JavaExpr> constMap, + CNumber resultType, + final StringBuilder javaExpr) { + final CNumber nValue = getANumber(constDef, sValue); + if( null != nValue ) { + resultType = evalType(resultType , nValue); + javaExpr.append(nValue.toJavaString()); + } else { + // Lookup CNumber type in const-map, to evaluate this result type + final JavaExpr cje = constMap.get(sValue); + if( null != cje ) { + resultType = evalType(resultType , cje.resultType); + } + javaExpr.append(sValue); + } + return resultType; + } + private static CNumber getANumber(final ConstantDefinition constDef, final String value) { + try { + final CNumber number = decodeANumber(value); + if( null != number ) { + return number; + } + } catch( final Throwable _t ) { + final String msg = "Cannot emit const \""+constDef.getName()+"\": value \""+value+ + "\" cannot be assigned to a int, long, float, or double"; + throw new GlueGenException(msg, constDef.getASTLocusTag(), _t); + } + return null; + } + private static CNumber evalType(final CNumber resultType, final CNumber type) { + //fast path + if( type.isDouble ) { + return type; + } + if( null != resultType ) { + if( resultType.isInteger ) { + if( resultType.isLong ) { + /* resultType is Long */ + if( !type.isInteger ) { + /* resultType: Long -> [ Float || Double ] */ + return type; + } + } else if( type.isLong || !type.isInteger ) { + /* resultType: Integer -> [ Long || Float || Double ] */ + return type; + } + } else if( !resultType.isInteger && !resultType.isDouble ) { + if( type.isDouble ) { + /* resultType: Float -> Double */ + return type; + } + } + } else { + return type; + } + return resultType; + } + } + private final boolean relaxedEqSem; - private final String sValue; - private final long iValue; - private final boolean hasIntValue; + private final String nativeExpr; + private final CNumber number; private final boolean isEnum; private final String enumName; private final ASTLocusTag astLocus; - /** Covering enums */ + /** + * Constructor for plain const-values, non-enumerates. + * @param name unique name of this constant expression + * @param nativeExpr original [native] expression + * @param number optional {@link CNumber} representing this constant. + * If {@code null}, implementation attempts to derive a {@link CNumber} + * of the given {@code nativeExpr}. + * @param astLocus AST location of the represented constant. + */ public ConstantDefinition(final String name, - final long value, - final String enumName, + final String nativeExpr, + final CNumber number, final ASTLocusTag astLocus) { - super(name); - this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); - this.sValue = String.valueOf(value); - this.iValue = value; - this.hasIntValue = true; - this.isEnum = true; - this.enumName = enumName; - this.astLocus = astLocus; + this(name, nativeExpr, number, false, null, astLocus); } - - /** Covering defines */ + /** + * Constructor for enumerates + * @param name unique name of this constant expression + * @param nativeExpr original [native] expression + * @param number optional {@link CNumber} representing this constant. + * If {@code null}, implementation attempts to derive a {@link CNumber} + * of the given {@code nativeExpr}. + * @param enumName optional name of the represented enumeration + * @param astLocus AST location of the represented constant. + */ public ConstantDefinition(final String name, - final String value, - final ASTLocusTag astLocus) { + final String nativeExpr, + final CNumber number, + final String enumName, final ASTLocusTag astLocus) { + this(name, nativeExpr, number, true, enumName, astLocus); + } + /** + * @param name unique name of this constant expression + * @param nativeExpr original [native] expression + * @param number optional {@link CNumber} representing this constant. + * If {@code null}, implementation attempts to derive a {@link CNumber} + * of the given {@code nativeExpr}. + * @param isEnum {@code true} if this constant is an enumerate, otherwise {@code false}. + * @param enumName optional name of the represented enumeration + * @param astLocus AST location of the represented constant. + */ + private ConstantDefinition(final String name, + final String nativeExpr, + final CNumber number, + final boolean isEnum, final String enumName, final ASTLocusTag astLocus) { super(name); + this.nativeExpr = nativeExpr; this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); - this.sValue = value; - { + if( null != number ) { + this.number = number; + } else { // Attempt to parse define string as number - long v; - boolean b; - try { - v = Long.decode(value).longValue(); - b = true; - } catch (final NumberFormatException e) { - v = 0; - b = false; + final CNumber iNum = decodeIntegerNumber(nativeExpr); + if( null != iNum ) { + this.number = iNum; + } else { + final CNumber fNum = decodeDecimalNumber(nativeExpr); + if( null != fNum ) { + this.number = fNum; + } else { + this.number = null; + } } - this.iValue = v; - this.hasIntValue = b; } - this.isEnum = false; - this.enumName = null; + this.isEnum = isEnum; + this.enumName = enumName; this.astLocus = astLocus; } @@ -122,8 +415,10 @@ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSema public final int hashCodeSemantics() { // 31 * x == (x << 5) - x int hash = 31 + ( null != getName() ? getName().hashCode() : 0 ); - hash = ((hash << 5) - hash) + ( null != sValue ? sValue.hashCode() : 0 ); - return ((hash << 5) - hash) + ( null != enumName ? enumName.hashCode() : 0 ); + hash = ((hash << 5) - hash) + ( isEnum ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( null != enumName ? enumName.hashCode() : 0 ); + hash = ((hash << 5) - hash) + ( null != number ? number.hashCode() : 0 ); + return ((hash << 5) - hash) + ( !relaxedEqSem && null != nativeExpr ? nativeExpr.hashCode() : 0 ); } @Override @@ -135,30 +430,49 @@ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSema } else { final ConstantDefinition t = (ConstantDefinition) arg; if( !equals(getName(), t.getName()) || + isEnum != t.isEnum || !equals(enumName, t.enumName) ) { return false; } - if( hasIntValue ) { - return iValue == t.iValue; + if( null != number ) { + if( number.isInteger ) { + return number.i == t.number.i; + } else { + return number.f == t.number.f; + } } else { // define's string value may be semantical equal .. but formatted differently! - return relaxedEqSem || equals(sValue, t.sValue); + return relaxedEqSem || equals(nativeExpr, t.nativeExpr); } } } - public String getValue() { return sValue; } - /** Returns null if this definition was not part of an - enumeration, or if the enum was anonymous. */ + /** Returns the original [native] expression. */ + public String getNativeExpr() { return nativeExpr; } + /** + * Returns the parsed {@link CNumber} of the {@link #getNativeExpr() native expression}, + * or {@code null} if the latter does not comprise a single number, + * i.e. is a complex expression. + */ + public CNumber getNumber() { return number; } + /** + * Returns {@code true} if this instance represents has a {@link #getNumber() number}, + * otherwise {@code false}. + */ + public boolean hasNumber() { return null != number; } + + /** Returns {@code null} if this definition was not part of an + enumeration, or if the enumeration is anonymous. */ public String getEnumName() { return enumName; } public boolean isEnum() { return isEnum; } @Override public String toString() { - return "ConstantDefinition [name " + getName() - + ", value " + sValue + " (isInt " + hasIntValue - + "), enumName " + enumName + ", isEnum " + isEnum + "]"; + return "ConstantDefinition [name \"" + getName() + + "\", expression \"" + nativeExpr + + "\", number "+number + + "], enum[is " + isEnum + ", name \"" + enumName + "\"]]"; } private static boolean equals(final String s1, final String s2) { @@ -172,6 +486,18 @@ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSema return s1.equals(s2); } + /** + * Computes the {@link JavaExpr java expression} based on this instance, + * see {@link JavaExpr#create(ConstantDefinition)}. + */ + public final JavaExpr computeJavaExpr(final Map<String, ConstantDefinition.JavaExpr> constMap) { + return JavaExpr.compute(this, constMap); + } + + // + // Static utility functions for type detection + // + public static boolean isConstantExpression(final String value) { if( null != value && value.length() > 0 ) { // Single numeric value @@ -222,32 +548,260 @@ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSema return identifier; } + /** + * Returns either {@link #decodeIntegerNumber(String)}, + * {@link #decodeDecimalNumber(String)} or {@code null}. + * @param v + */ + public static CNumber decodeANumber(final String v) { + final CNumber iNumber = ConstantDefinition.decodeIntegerNumber(v); + if( null != iNumber ) { + return iNumber; + } + return ConstantDefinition.decodeDecimalNumber(v); + } + + /** + * If the given string {@link #isIntegerNumber(String)}, + * return the decoded integer value, represented as a {@code ANumber}, + * otherwise returns {@code null}. + * <p> + * Method strips off sign prefix {@code +} + * and integer modifier suffixes {@code [uUlL]} + * before utilizing {@link Long#decode(String)}. + * </p> + * @param v + */ + public static CNumber decodeIntegerNumber(final String v) { + if( null == v || !isIntegerNumber(v) ) { + return null; + } + String s0 = v.trim(); + if( 0 == s0.length() ) { + return null; + } + if (s0.startsWith("+")) { + s0 = s0.substring(1, s0.length()).trim(); + if( 0 == s0.length() ) { + return null; + } + } + final boolean neg; + if (s0.startsWith("-")) { + s0 = s0.substring(1, s0.length()).trim(); + if( 0 == s0.length() ) { + return null; + } + neg = true; + } else { + neg = false; + } + + // Test last two chars for [lL] and [uU] modifiers! + boolean isUnsigned = false; + boolean isLong = false; + final int j = s0.length() - 2; + for(int i = s0.length() - 1; i >= 0 && i >= j; i--) { + final char lastChar = s0.charAt(s0.length()-1); + if( lastChar == 'u' || lastChar == 'U' ) { + s0 = s0.substring(0, s0.length()-1); + isUnsigned = true; + } else if( lastChar == 'l' || lastChar == 'L' ) { + s0 = s0.substring(0, s0.length()-1); + isLong = true; + } else { + // early out, no modifier match! + break; + } + } + if( 0 == s0.length() ) { + return null; + } + final long res; + if( isLong && isUnsigned ) { + res = decodeULong(s0, neg); + } else { + if( neg ) { + s0 = "-" + s0; + } + res = Long.decode(s0).longValue(); + } + final boolean isLong2 = isLong || + ( !isUnsigned && ( Integer.MIN_VALUE > res || res > Integer.MAX_VALUE ) ) || + ( isUnsigned && res > UNSIGNED_INT_MAX_VALUE ); + return new CNumber(isLong2, isUnsigned, res); + } + private static long decodeULong(final String v, final boolean neg) throws NumberFormatException { + final int radix; + final int idx; + if (v.startsWith("0x") || v.startsWith("0X")) { + idx = 2; + radix = 16; + } else if (v.startsWith("#")) { + idx = 1; + radix = 16; + } else if (v.startsWith("0") && v.length() > 1) { + idx = 1; + radix = 8; + } else { + idx = 0; + radix = 10; + } + final String s0 = ( neg ? "-" : "" ) + v.substring(idx); + final BigInteger res = new BigInteger(s0, radix); + if( res.compareTo(UNSIGNED_LONG_MAX_VALUE) > 0 ) { + throw new NumberFormatException("Value \""+v+"\" is > UNSIGNED_LONG_MAX"); + } + return res.longValue(); + } + + /** + * If the given string {@link #isDecimalNumber(String)}, + * return the decoded floating-point value, represented as a {@code ANumber} object, + * otherwise returns {@code null}. + * <p> + * Method utilizes {@link Double#valueOf(String)}. + * </p> + * @param v + * @param isDouble return value for {@code double} flag + */ + public static CNumber decodeDecimalNumber(final String v) { + if( null == v || !isDecimalNumber(v) ) { + return null; + } + final String s0 = v.trim(); + if( 0 == s0.length() ) { + return null; + } + boolean _isDouble = false; + final char lastChar = s0.charAt(s0.length()-1); + if( lastChar == 'd' || lastChar == 'D' ) { + _isDouble = true; + } + final double res = Double.valueOf(s0).doubleValue(); + final double ares = Math.abs(res); + return new CNumber(_isDouble || Float.MIN_VALUE > ares || ares > Float.MAX_VALUE, res); + } + + /** + * Matches {@link #isHexNumber(String)} or {@link #isDecimalOrIntNumber(String)}. + */ public static boolean isNumber(final String s) { if( isHexNumber(s) ) { return true; } else { - return isDecimalNumber(s); + return isDecimalOrIntNumber(s); + } + } + + /** + * Matches {@link #isHexNumber(String)} or {@link #patternIntegerNumber}. + */ + public static boolean isIntegerNumber(final String s) { + if( isHexNumber(s) ) { + return true; + } else { + return patternIntegerNumber.matcher(s).matches(); } } + + /** + * Matches {@link #patternHexNumber}. + */ public static boolean isHexNumber(final String s) { return patternHexNumber.matcher(s).matches(); } - public static Pattern patternHexNumber = Pattern.compile("0[xX][0-9a-fA-F]+[lLfFuU]?"); + + /** + * Matches pattern for <code>floating point</code> number, + * compatible and described in {@link Double#valueOf(String)}. + */ + public static boolean isDecimalNumber(final String s) { + return patternDecimalNumber.matcher(s).matches(); + } + + /** + * Complete pattern for <code>floating point</code> <i>and</i> <code>integer</code> number, + * covering {@link #patternDecimalNumber} <i>and</i> {@link #patternIntegerNumber}. + */ + public static boolean isDecimalOrIntNumber(final String s) { + return patternDecimalOrIntNumber.matcher(s).matches(); + } + + /** + * Matches pattern for valid CPP operands, see {@link #patternCPPOperand}. + */ + public static boolean isCPPOperand(final String s) { + return patternCPPOperand.matcher(s).matches(); + } + + /** + * Complete pattern for <code>hexadecimal</code> number, + * including an optional sign {@code [+-]} and optional suffixes {@code [uUlL]}. + */ + public static Pattern patternHexNumber; /** * Complete pattern for <code>floating point</code> number, * compatible and described in {@link Double#valueOf(String)}. */ - public static Pattern patternDecimalNumber; - private static String fpRegex; + public final static Pattern patternDecimalNumber; + + /** + * Complete pattern for <code>floating point</code> <i>and</i> <code>integer</code> number, + * covering {@link #patternDecimalNumber} <i>and</i> {@link #patternIntegerNumber}. + */ + public final static Pattern patternDecimalOrIntNumber; + + /** + * Complete pattern for <code>integer</code> number, + * including an optional sign {@code [+-]} and optional suffixes {@code [uUlL]}. + */ + public final static Pattern patternIntegerNumber; + + /** + * One of: {@code +} {@code -} {@code *} {@code /} {@code |} {@code &} {@code (} {@code )} {@code <<} {@code >>} + * <p> + * Expression excludes {@link #patternDecimalOrIntNumber}. + * </p> + */ + public static Pattern patternCPPOperand; + static { + final String WhiteSpace = "[\\x00-\\x20]*"; final String Digits = "(\\p{Digit}+)"; final String HexDigits = "(\\p{XDigit}+)"; + final String IntTypeSuffix = + "(" + + "[uU]|" + + "([uU][lL])|" + + "[lL]|" + + "([lL][uU])" + + ")"; + + final String hexRegex = + WhiteSpace + // Optional leading "whitespace" + "[+-]?" + // Optional sign character + // HexDigits IntTypeSuffix_opt + "0[xX]" + HexDigits + IntTypeSuffix + "?" + + WhiteSpace // Optional trailing "whitespace" + ; + patternHexNumber = Pattern.compile(hexRegex); + + final String intRegex = + WhiteSpace + // Optional leading "whitespace" + "[+-]?" + // Optional sign character + // Digits IntTypeSuffix_opt + Digits + IntTypeSuffix + "?" + + WhiteSpace // Optional trailing "whitespace" + ; + patternIntegerNumber = Pattern.compile(intRegex); + // an exponent is 'e' or 'E' followed by an optionally // signed decimal integer. final String Exp = "[eE][+-]?"+Digits; - fpRegex = - ("[\\x00-\\x20]*"+ // Optional leading "whitespace" + final String fpRegex = + WhiteSpace + // Optional leading "whitespace" "[+-]?" + // Optional sign character "("+ "NaN|" + // "NaN" string @@ -289,23 +843,112 @@ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSema "[fFdD]?"+ ")"+ ")" + - "[\\x00-\\x20]*"// Optional trailing "whitespace" - ); + WhiteSpace // Optional trailing "whitespace" + ; patternDecimalNumber = Pattern.compile(fpRegex); - } - public static boolean isDecimalNumber(final String s) { - return patternDecimalNumber.matcher(s).matches(); - } - public static boolean isCPPOperand(final String s) { - return patternCPPOperand.matcher(s).matches(); - } - /** - * One of: {@code +} {@code -} {@code *} {@code /} {@code |} {@code &} {@code (} {@code )} {@code <<} {@code >>} - * <p> - * Expression excludes {@link #patternDecimalNumber}. - * </p> - */ - public static Pattern patternCPPOperand = Pattern.compile("(?!"+fpRegex+")[\\+\\-\\*\\/\\|\\&\\(\\)]|(\\<\\<)|(\\>\\>)"); + final String fpOrIntRegex = + WhiteSpace + // Optional leading "whitespace" + "[+-]?" + // Optional sign character + "("+ + "NaN|" + // "NaN" string + "Infinity|" + // "Infinity" string + + // Matching integers w/ IntTypeSuffix, + // which are otherwise not matched by the below floating point matcher! + // Digits IntTypeSuffix + "(" + Digits + IntTypeSuffix +")|" + + + // A decimal floating-point string representing a finite positive + // number without a leading sign has at most five basic pieces: + // Digits . Digits ExponentPart FloatTypeSuffix + // + // Since this method allows integer-only strings as input + // in addition to strings of floating-point literals, the + // two sub-patterns below are simplifications of the grammar + // productions from the Java Language Specification, 2nd + // edition, section 3.10.2. + + "("+ + "("+ + // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt + "(" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" + + // . Digits ExponentPart_opt FloatTypeSuffix_opt + "(\\.(" + Digits + ")(" + Exp + ")?)|" + + + // Hexadecimal w/ binary exponent + "(" + + "(" + + // Hexadecimal strings + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "(\\.)?)|" + + + // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + + ")" + + + // binary exponent + "[pP][+-]?" + Digits + + ")" + + ")" + + "[fFdD]?"+ + ")"+ + ")" + + WhiteSpace // Optional trailing "whitespace" + ; + patternDecimalOrIntNumber = Pattern.compile(fpOrIntRegex); + + final String fpOrIntRegex2 = + WhiteSpace + // Optional leading "whitespace" + // "[+-]?" + // Optional sign character + "("+ + "NaN|" + // "NaN" string + "Infinity|" + // "Infinity" string + + // Matching integers w/ IntTypeSuffix, + // which are otherwise not matched by the below floating point matcher! + // Digits IntTypeSuffix + "(" + Digits + IntTypeSuffix +")|" + + + // A decimal floating-point string representing a finite positive + // number without a leading sign has at most five basic pieces: + // Digits . Digits ExponentPart FloatTypeSuffix + // + // Since this method allows integer-only strings as input + // in addition to strings of floating-point literals, the + // two sub-patterns below are simplifications of the grammar + // productions from the Java Language Specification, 2nd + // edition, section 3.10.2. + + "("+ + "("+ + // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt + "(" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" + + + // . Digits ExponentPart_opt FloatTypeSuffix_opt + "(\\.(" + Digits + ")(" + Exp + ")?)|" + + + // Hexadecimal w/ binary exponent + "(" + + "(" + + // Hexadecimal strings + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "(\\.)?)|" + + + // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + + ")" + + + // binary exponent + "[pP][+-]?" + Digits + + ")" + + ")" + + "[fFdD]?"+ + ")"+ + ")" + + WhiteSpace // Optional trailing "whitespace" + ; + patternCPPOperand = Pattern.compile("(?!"+fpOrIntRegex2+")[\\+\\-\\*\\/\\|\\&\\(\\)]|(\\<\\<)|(\\>\\>)"); + } } diff --git a/src/java/com/jogamp/gluegen/DebugEmitter.java b/src/java/com/jogamp/gluegen/DebugEmitter.java index 582a1d7..046c2b6 100644 --- a/src/java/com/jogamp/gluegen/DebugEmitter.java +++ b/src/java/com/jogamp/gluegen/DebugEmitter.java @@ -74,7 +74,7 @@ public class DebugEmitter implements GlueEmitter { @Override public void emitDefine(final ConstantDefinition def, final String optionalComment) { final String name = def.getName(); - final String value = def.getValue(); + final String value = def.getNativeExpr(); System.out.println("#define " + name + " " + value + (optionalComment != null ? ("// " + optionalComment) : "")); } diff --git a/src/java/com/jogamp/gluegen/GlueGen.java b/src/java/com/jogamp/gluegen/GlueGen.java index d0ce9ed..6dee6f0 100644 --- a/src/java/com/jogamp/gluegen/GlueGen.java +++ b/src/java/com/jogamp/gluegen/GlueGen.java @@ -217,14 +217,17 @@ public class GlueGen implements GlueEmitterControls { } // iterate over all values in the enumeration for (int i = 0; i < enumeration.getNumEnumerates(); ++i) { - final String enumElementName = enumeration.getEnumName(i); - allConstants.add(new ConstantDefinition(enumElementName, enumeration.getEnumValue(i), - enumName, enumeration.getASTLocusTag())); + final EnumType.Enumerator enumerate = enumeration.getEnum(i); + final ConstantDefinition def = + new ConstantDefinition(enumerate.getName(), enumerate.getExpr(), + enumerate.getNumber(), + enumName, enumeration.getASTLocusTag()); + allConstants.add(def); } } for (final Object elem : lexer.getDefines()) { final Define def = (Define) elem; - allConstants.add(new ConstantDefinition(def.getName(), def.getValue(), def.getASTLocusTag())); + allConstants.add(new ConstantDefinition(def.getName(), def.getValue(), null, def.getASTLocusTag())); } allConstants.addAll(preprocessor.getConstantDefinitions()); diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index 15dc401..60cd3f4 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -40,24 +40,56 @@ package com.jogamp.gluegen; +import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PACKAGE_PRIVATE; +import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PRIVATE; +import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PROTECTED; +import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PUBLIC; +import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PUBLIC_ABSTRACT; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.Buffer; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jogamp.common.os.MachineDataInfoRuntime; + import com.jogamp.common.nio.Buffers; import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.os.MachineDataInfo; - -import java.io.*; -import java.util.*; -import java.text.MessageFormat; - +import com.jogamp.common.util.ArrayHashMap; import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider; import com.jogamp.gluegen.Logging.LoggerIf; -import com.jogamp.gluegen.cgram.types.*; +import com.jogamp.gluegen.cgram.types.AliasedSymbol; +import com.jogamp.gluegen.cgram.types.ArrayType; +import com.jogamp.gluegen.cgram.types.CVAttributes; +import com.jogamp.gluegen.cgram.types.CompoundType; +import com.jogamp.gluegen.cgram.types.Field; +import com.jogamp.gluegen.cgram.types.FunctionSymbol; +import com.jogamp.gluegen.cgram.types.FunctionType; +import com.jogamp.gluegen.cgram.types.IntType; +import com.jogamp.gluegen.cgram.types.PointerType; +import com.jogamp.gluegen.cgram.types.SizeThunk; +import com.jogamp.gluegen.cgram.types.StructLayout; +import com.jogamp.gluegen.cgram.types.Type; import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; - -import java.nio.Buffer; - -import jogamp.common.os.MachineDataInfoRuntime; -import static java.util.logging.Level.*; -import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*; +import com.jogamp.gluegen.cgram.types.TypeDictionary; // PROBLEMS: // - what if something returns 'const int *'? Could we @@ -134,9 +166,12 @@ public class JavaEmitter implements GlueEmitter { return functions; } - private <T extends AliasedSemanticSymbol> List<T> filterSymbolsInt(final List<T> inList, final List<T> outList) { + private <T extends AliasedSemanticSymbol> List<T> filterSymbolsInt(final List<T> inList, + final boolean preserveOrder, + final List<T> outList) { final JavaConfiguration cfg = getConfig(); - final HashMap<String, T> symMap = new HashMap<String, T>(100); + final ArrayHashMap<String, T> symMap = + new ArrayHashMap<String, T>(false, 100, ArrayHashMap.DEFAULT_LOAD_FACTOR); for (final T sym : inList) { final String origName = sym.getName(); final String newName = cfg.getJavaSymbolRename(origName); @@ -195,21 +230,23 @@ public class JavaEmitter implements GlueEmitter { } } } - outList.addAll(symMap.values()); - // sort constants to make them easier to find in native code - Collections.sort(outList, new Comparator<T>() { - @Override - public int compare(final T o1, final T o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + outList.addAll(symMap.getData()); + if( !preserveOrder ) { + // sort constants to make them easier to find in native code + Collections.sort(outList, new Comparator<T>() { + @Override + public int compare(final T o1, final T o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + } return outList; } @Override public void filterSymbols(final List<ConstantDefinition> inConstList, final List<FunctionSymbol> inFuncList) { - constants = filterSymbolsInt(inConstList, new ArrayList<ConstantDefinition>(100)); - functions = filterSymbolsInt(inFuncList, new ArrayList<FunctionSymbol>(100)); + constants = filterSymbolsInt(inConstList, true, new ArrayList<ConstantDefinition>(100)); + functions = filterSymbolsInt(inFuncList, true, new ArrayList<FunctionSymbol>(100)); } } @@ -253,171 +290,6 @@ public class JavaEmitter implements GlueEmitter { } } - protected static int getJavaRadix(final String name, final String value) { - // FIXME: need to handle when type specifier is in last char (e.g., - // "1.0d or 2759L", because parseXXX() methods don't allow the type - // specifier character in the string. - // - //char lastChar = value.charAt(value.length()-1); - - try { - // see if it's a long or int - int radix; - String parseValue; - // FIXME: are you allowed to specify hex/octal constants with - // negation, e.g. "-0xFF" or "-056"? If so, need to modify the - // following "if(..)" checks and parseValue computation - if (value.startsWith("0x") || value.startsWith("0X")) { - radix = 16; - parseValue = value.substring(2); - } - else if (value.startsWith("0") && value.length() > 1) { - // TODO: is "0" the prefix in C to indicate octal??? - radix = 8; - parseValue = value.substring(1); - } - else { - radix = 10; - parseValue = value; - } - //System.err.println("parsing " + value + " as long w/ radix " + radix); - Long.parseLong(parseValue, radix); - return radix; - } catch (final NumberFormatException e) { - try { - // see if it's a double or float - Double.parseDouble(value); - return 10; - } catch (final NumberFormatException e2) { - throw new RuntimeException( - "Cannot emit define \""+name+"\": value \""+value+ - "\" cannot be assigned to a int, long, float, or double", e2); - } - } - } - - protected static Object getJavaValue(final String name, final String value) { - - // "calculates" the result type of a simple expression - // example: (2+3)-(2.0f-3.0) -> Double - // example: (1 << 2) -> Integer - final Scanner scanner = new Scanner(value).useDelimiter(ConstantDefinition.patternCPPOperand); - - Object resultType = null; - - while (scanner.hasNext()) { - - final String t = scanner.next().trim(); - - if(0<t.length()) { - final Object type = getJavaValue2(name, t); - - //fast path - if(type instanceof Double) - return type; - - if(resultType != null) { - - if(resultType instanceof Integer) { - if(type instanceof Long || type instanceof Float || type instanceof Double) - resultType = type; - }else if(resultType instanceof Long) { - if(type instanceof Float || type instanceof Double) - resultType = type; - }else if(resultType instanceof Float) { - if(type instanceof Float) - resultType = type; - } - }else{ - resultType = type; - } - - //fast path - if(resultType instanceof Double) - return type; - } - } - - return resultType; - } - - private static Object getJavaValue2(final String name, final String value) { - // FIXME: need to handle when type specifier is in last char (e.g., - // "1.0d or 2759L", because parseXXX() methods don't allow the type - // specifier character in the string. - // - final char lastChar = value.charAt(value.length()-1); - - try { - // see if it's a long or int - int radix; - String parseValue; - // FIXME: are you allowed to specify hex/octal constants with - // negation, e.g. "-0xFF" or "-056"? If so, need to modify the - // following "if(..)" checks and parseValue computation - if (value.startsWith("0x") || value.startsWith("0X")) { - radix = 16; - parseValue = value.substring(2); - } else if (value.startsWith("0") && value.length() > 1) { - // TODO: is "0" the prefix in C to indicate octal??? - radix = 8; - parseValue = value.substring(1); - } else { - radix = 10; - parseValue = value; - } - if(lastChar == 'u' || lastChar == 'U') { - parseValue = parseValue.substring(0, parseValue.length()-1); - } - - //System.err.println("parsing " + value + " as long w/ radix " + radix); - final long longVal = Long.parseLong(parseValue, radix); - // if constant is small enough, store it as an int instead of a long - if (longVal > Integer.MIN_VALUE && longVal < Integer.MAX_VALUE) { - return (int)longVal; - } - return longVal; - - } catch (final NumberFormatException e) { - try { - // see if it's a double or float - final double dVal = Double.parseDouble(value); - final double absVal = Math.abs(dVal); - // if constant is small enough, store it as a float instead of a double - if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE || lastChar == 'd' || lastChar == 'D' ) { - return new Double(dVal); - } - return new Float((float) dVal); - } catch (final NumberFormatException e2) { - throw new RuntimeException( - "Cannot emit define \""+name+"\": value \""+value+ - "\" cannot be assigned to a int, long, float, or double", e2); - } - } - } - - - protected static String getJavaType(final String name, final String value) { - final Object oval = getJavaValue(name, value); - return getJavaType(name, oval); - } - - protected static String getJavaType(final String name, final Object oval) { - if(oval instanceof Integer) { - return "int"; - } else if(oval instanceof Long) { - return "long"; - } else if(oval instanceof Float) { - return "float"; - } else if(oval instanceof Double) { - return "double"; - } - - throw new RuntimeException( - "Cannot emit define (2) \""+name+"\": value \""+oval+ - "\" cannot be assigned to a int, long, float, or double"); - } - /** Mangle a class, package or function name for JNI usage, i.e. replace all '.' w/ '_' */ protected static String jniMangle(final String name) { return name.replaceAll("_", "_1").replace('.', '_'); @@ -427,6 +299,9 @@ public class JavaEmitter implements GlueEmitter { return "Java_"+jniMangle(javaPackageName)+"_"+jniMangle(javaClassName); } + private final Map<String, ConstantDefinition.JavaExpr> constMap = + new HashMap<String, ConstantDefinition.JavaExpr>(); + @Override public void emitDefine(final ConstantDefinition def, final String optionalComment) throws Exception { if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) { @@ -439,24 +314,22 @@ public class JavaEmitter implements GlueEmitter { // currently only emits only numeric defines -- if it handled #define'd // objects it would make a bigger difference. - final String name = def.getName(); - String value = def.getValue(); - if ( !cfg.shouldIgnoreInInterface(def) ) { - final String type = getJavaType(name, value); + final ConstantDefinition.JavaExpr constExpr = def.computeJavaExpr(constMap); + constMap.put(def.getName(), constExpr); + javaWriter().print(" /** "); if (optionalComment != null && optionalComment.length() != 0) { - javaWriter().println(" /** " + optionalComment + " */"); + javaWriter().print(optionalComment); + javaWriter().print(" - "); } - String suffix = ""; - final char lastChar = value.charAt(value.length()-1); - if( lastChar != ')' ) { - if (type.equals("float") && lastChar != 'f' && lastChar != 'F' ) { - suffix = "f"; - }else if( lastChar == 'u' || lastChar == 'U' ) { - value = value.substring(0, value.length()-1); - } + javaWriter().print("CType: "); + if( constExpr.resultType.isUnsigned ) { + javaWriter().print("unsigned "); } - javaWriter().println(" public static final " + type + " " + name + " = " + value + suffix + ";"); + javaWriter().print(constExpr.resultJavaTypeName); + javaWriter().println(" */"); + javaWriter().println(" public static final " + constExpr.resultJavaTypeName + + " " + def.getName() + " = " + constExpr.javaExpression + ";"); } } } diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java index c145ff5..d3fca14 100644 --- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java @@ -894,7 +894,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { writer.print(" valid values are: <code>"); for (int j = 0; j < enumType.getNumEnumerates(); ++j) { if (j>0) writer.print(", "); - writer.print(enumType.getEnumName(j)); + writer.print(enumType.getEnum(j).getName()); } writer.println("</code>"); } else if (javaType.isNIOBuffer()) { diff --git a/src/java/com/jogamp/gluegen/cgram/TNode.java b/src/java/com/jogamp/gluegen/cgram/TNode.java index 70dc2c4..5a36945 100644 --- a/src/java/com/jogamp/gluegen/cgram/TNode.java +++ b/src/java/com/jogamp/gluegen/cgram/TNode.java @@ -10,6 +10,7 @@ import java.util.Enumeration; import com.jogamp.gluegen.ASTLocusTag; import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider; +import com.jogamp.gluegen.GlueGen; /** Class TNode is an implementation of the AST interface @@ -179,15 +180,87 @@ public void initialize(final AST tr) { text = text_; } - /** Returns the text for this node and all children */ - public String getAllChildrenText() { + static class DebugASTVisitor { + protected int level; + private String tabs(final StringBuilder sb) { + sb.setLength(0); + for (int i = 0; i < level; i++) { + sb.append(" "); + } + return sb.toString(); + } + DebugASTVisitor(final int level) { + this.level = level; + } + void visit(final AST node) { + final StringBuilder sb = new StringBuilder(); + AST node2; + for (node2 = node; node2 != null; node2 = node2.getNextSibling()) { + if (node2.getText() == null) { + System.err.printf("%03d: %snil [%d]%n", level, tabs(sb), node2.getType()); + } else { + System.err.printf("%03d: %s%s [%d]%n", level, tabs(sb), node2.getText(), node2.getType()); + } + if (node2.getFirstChild() != null) { + level++; + visit(node2.getFirstChild()); + level--; + } + } + } + } + + /** + * Returns the text for this node, its children and siblings. + * <p> + * Implementation converts the AST LISP notation to serialized form. + * </p> + */ + public String getAllChildrenText(final String name) { + if( GlueGen.debug() ) { + System.err.println("TNode.XXX: "+name); + new DebugASTVisitor(1).visit(getFirstChild()); + } final StringBuilder buf = new StringBuilder(); - buf.append(getText()); - for (TNode node = (TNode) getFirstChild(); node != null; node = (TNode) node.getNextSibling()) { - buf.append(node.getText()); + final TNode down = (TNode) this.getFirstChild(); + if( null == down ) { + buf.append(this.getText()); + } else { + getAllChildrenText(buf, this, down); } return buf.toString(); } + private static void getAllChildrenText(final StringBuilder buf, + final TNode upNode, TNode thisNode) { + boolean first = true; + while( null != thisNode ) { + final boolean isClosing = HeaderParserTokenTypes.RPAREN == thisNode.getType(); + final boolean isGroupStart = HeaderParserTokenTypes.NExpressionGroup == thisNode.getType(); + + final TNode nextNode = (TNode) thisNode.getNextSibling(); + final TNode downNode = (TNode) thisNode.getFirstChild(); + if( !isClosing && + ( null == downNode && null == nextNode || // unary + !first // binary + ) + ) { + buf.append(" ").append(upNode.getText()); + } + if( null != downNode ) { + if( !isGroupStart ) { + buf.append(" ("); + } + getAllChildrenText(buf, thisNode, downNode); + if( !isGroupStart ) { + buf.append(" )"); + } + } else if( !isClosing ) { + buf.append(" ").append(thisNode.getText()); + } + thisNode = nextNode; + first = false; + } + } /** return the last child of this node, or null if there is none */ public TNode getLastChild() { diff --git a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java index f49c2ec..7c2fa73 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java @@ -43,6 +43,9 @@ import java.util.ArrayList; import java.util.NoSuchElementException; import com.jogamp.gluegen.ASTLocusTag; +import com.jogamp.gluegen.ConstantDefinition; +import com.jogamp.gluegen.ConstantDefinition.CNumber; +import com.jogamp.gluegen.GlueGenException; import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; @@ -50,40 +53,49 @@ import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; they have a set of named values. */ public class EnumType extends IntType implements Cloneable { - private static class Enum implements TypeComparator.SemanticEqualityOp { - final String name; - final long value; + public static class Enumerator implements TypeComparator.SemanticEqualityOp { + private final String name; + private final String expr; + private final CNumber number; - Enum(final String name, final long value) { + public Enumerator(final String name, final long value) { this.name = name; - this.value = value; + this.number = new CNumber(false, false, value); + this.expr = this.number.toJavaString(); } - - String getName() { - return name; + public Enumerator(final String name, final CNumber number) { + this.name = name; + this.number = number; + this.expr = this.number.toJavaString(); } - - long getValue() { - return value; + public Enumerator(final String name, final String value) { + this.name = name; + this.expr = value; + this.number = ConstantDefinition.decodeIntegerNumber(value); } + public String getName() { return name; } + public String getExpr() { return expr; } + public CNumber getNumber() { return number; } + public boolean hasNumber() { return null != number; } + @Override public int hashCode() { // 31 * x == (x << 5) - x final int hash = name.hashCode(); - return ((hash << 5) - hash) + (int)(value ^ (value >>> 32)); + return ((hash << 5) - hash) + expr.hashCode(); } @Override public boolean equals(final Object arg) { if (arg == this) { return true; - } else if ( !(arg instanceof Enum) ) { + } else if ( !(arg instanceof Enumerator) ) { return false; } - final Enum t = (Enum) arg; + final Enumerator t = (Enumerator) arg; return name.equals(t.name) && - value == t.value; + expr.equals(t.expr); } @Override @@ -96,11 +108,12 @@ public class EnumType extends IntType implements Cloneable { return equals(arg); } - public String toString() { return name+" = "+value; } + @Override + public String toString() { return "["+name+" = ["+expr+", "+number+"]"; } } private final IntType underlyingType; - private ArrayList<Enum> enums; + private ArrayList<Enumerator> enums; public EnumType(final String name) { super(name, SizeThunk.LONG, false, CVAttributes.CONST); @@ -116,7 +129,7 @@ public class EnumType extends IntType implements Cloneable { super(o, cvAttributes, astLocus); underlyingType = o.underlyingType; if(null != o.enums) { - enums = new ArrayList<Enum>(o.enums); + enums = new ArrayList<Enumerator>(o.enums); } } @@ -164,11 +177,11 @@ public class EnumType extends IntType implements Cloneable { public Type getUnderlyingType() { return this.underlyingType; } - public void addEnum(final String name, final long val) { + public void addEnum(final String name, final Enumerator newEnum) { if (enums == null) { - enums = new ArrayList<Enum>(); + enums = new ArrayList<Enumerator>(); } - enums.add(new Enum(name, val)); + enums.add(newEnum); clearCache(); } @@ -177,22 +190,17 @@ public class EnumType extends IntType implements Cloneable { return enums.size(); } - /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) name */ - public String getEnumName(final int i) { - return (enums.get(i)).getName(); - } - - /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) value */ - public long getEnumValue(final int i) { - return (enums.get(i)).getValue(); + /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) {@link Enumerator} */ + public Enumerator getEnum(final int i) { + return enums.get(i); } - /** Fetch the value of the enumerate with the given name. */ - public long getEnumValue(final String name) { + /** Fetch the enumerate with the given name. */ + public Enumerator getEnum(final String name) { for (int i = 0; i < enums.size(); ++i) { - final Enum n = (enums.get(i)); + final Enumerator n = (enums.get(i)); if (n.getName().equals(name)) { - return n.getValue(); + return n; } } throw new NoSuchElementException( @@ -215,7 +223,7 @@ public class EnumType extends IntType implements Cloneable { */ public boolean removeEnumerate(final String name) { for (int i = 0; i < enums.size(); ++i) { - final Enum e = enums.get(i); + final Enumerator e = enums.get(i); if (e.getName().equals(name)) { enums.remove(e); clearCache(); |