/* * Copyright (c) 2008 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. * */ package com.jogamp.gluegen; import java.util.regex.Pattern; import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider; 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. */ public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSemanticSymbol, ASTLocusTagProvider { private final boolean relaxedEqSem; private final String sValue; private final long iValue; private final boolean hasIntValue; private final boolean isEnum; private final String enumName; private final ASTLocusTag astLocus; /** Covering enums */ public ConstantDefinition(final String name, final long value, final String enumName, 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; } /** Covering defines */ public ConstantDefinition(final String name, final String value, final ASTLocusTag astLocus) { super(name); this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); this.sValue = value; { // 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; } this.iValue = v; this.hasIntValue = b; } this.isEnum = false; this.enumName = null; this.astLocus = astLocus; } @Override public ASTLocusTag getASTLocusTag() { return astLocus; } /** * Hash by its given {@link #getName() name}. */ @Override public final int hashCode() { return getName().hashCode(); } /** * Equality test by its given {@link #getName() name}. */ @Override public final boolean equals(final Object arg) { if (arg == this) { return true; } else if ( !(arg instanceof ConstantDefinition) ) { return false; } else { final ConstantDefinition t = (ConstantDefinition)arg; return equals(getName(), t.getName()); } } @Override 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 ); } @Override public final boolean equalSemantics(final SemanticEqualityOp arg) { if (arg == this) { return true; } else if ( !(arg instanceof ConstantDefinition) ) { return false; } else { final ConstantDefinition t = (ConstantDefinition) arg; if( !equals(getName(), t.getName()) || !equals(enumName, t.enumName) ) { return false; } if( hasIntValue ) { return iValue == t.iValue; } else { // define's string value may be semantical equal .. but formatted differently! return relaxedEqSem || equals(sValue, t.sValue); } } } public String getValue() { return sValue; } /** Returns null if this definition was not part of an enumeration, or if the enum was 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 + "]"; } private static boolean equals(final String s1, final String s2) { if (s1 == null || s2 == null) { if (s1 == null && s2 == null) { return true; } return false; } return s1.equals(s2); } public static boolean isConstantExpression(final String value) { if( null != value && value.length() > 0 ) { // Single numeric value if ( isNumber(value) ) { return true; } // Find constant expressions like (1 << 3) // if found just pass them through, they will most likely work in java too // expressions containing identifiers are currently ignored (casts too) final String[] values = value.split("[\\s\\(\\)]"); // [ whitespace '(' ')' ] int numberCount = 0; for (final String s : values) { if( s.length() > 0 ) { if( isCPPOperand(s) ) { // OK } else if ( isNumber(s) ) { // OK numberCount++; } else { return false; } } } final boolean res = numberCount > 0; return res; } return false; } public static boolean isIdentifier(final String value) { boolean identifier = false; final char[] chars = value.toCharArray(); for (int i = 0; i < chars.length; i++) { final char c = chars[i]; if (i == 0) { if (Character.isJavaIdentifierStart(c)) { identifier = true; } } else { if (!Character.isJavaIdentifierPart(c)) { identifier = false; break; } } } return identifier; } public static boolean isNumber(final String s) { if( isHexNumber(s) ) { return true; } else { return isDecimalNumber(s); } } 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]?"); /** * Complete pattern for floating point number, * compatible and described in {@link Double#valueOf(String)}. */ public static Pattern patternDecimalNumber; private static String fpRegex; static { final String Digits = "(\\p{Digit}+)"; final String HexDigits = "(\\p{XDigit}+)"; // an exponent is 'e' or 'E' followed by an optionally // signed decimal integer. final String Exp = "[eE][+-]?"+Digits; fpRegex = ("[\\x00-\\x20]*"+ // Optional leading "whitespace" "[+-]?" + // Optional sign character "("+ "NaN|" + // "NaN" string "Infinity|" + // "Infinity" string // 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]?"+ ")"+ ")" + "[\\x00-\\x20]*"// 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 >>} *

* Expression excludes {@link #patternDecimalNumber}. *

*/ public static Pattern patternCPPOperand = Pattern.compile("(?!"+fpRegex+")[\\+\\-\\*\\/\\|\\&\\(\\)]|(\\<\\<)|(\\>\\>)"); }