* Thomas Corbat (IFS)
* Nathan Ridge
* Marc-Andre Laperle
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
+import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
assertTrue("Expected types to be the same, but first was: '" + first.toString() + "' and second was: '" + second + "'", first.isSameType(second));
}
+ private void checkUserDefinedLiteralIsType(String code, String type_name) throws Exception {
+ IASTTranslationUnit tu = parseAndCheckBindings(code, CPP);
+ IASTDeclaration[] declarations = tu.getDeclarations();
+ IASTDeclaration declaration = declarations[declarations.length - 1];
+
+ IASTInitializer init = ((IASTSimpleDeclaration) declaration).getDeclarators()[0].getInitializer();
+ IType type = ((IASTExpression)((IASTEqualsInitializer) init).getInitializerClause()).getExpressionType();
+
+ assertEquals(type_name, type.toString());
+ }
+
+ private void checkUserDefinedLiteralIsRet(String code) throws Exception {
+ checkUserDefinedLiteralIsType(code, "Ret");
+ }
+
// int *zzz1 (char);
// int (*zzz2) (char);
// int ((*zzz3)) (char);
public void testAlignas_451082() throws Exception {
parseAndCheckBindings();
}
+
+ // int operator "" _A(unsigned long long i) { return 1; }
+ // int operator "" _B(long double d) { return 1; }
+ // int operator "" _C(const char* s, unsigned int sz) { return sz; }
+ // int operator "" _D(const wchar_t* s, unsigned int sz) { return sz; }
+ // int operator "" _E(const char16_t* s, unsigned int sz) { return sz; }
+ // int operator "" _F(const char32_t* s, unsigned int sz) { return sz; }
+ // int operator "" _G(char c) { return (int)c; }
+ // constexpr double operator "" _km_to_miles(long double km) { return km * 0.6213; }
+ public void testSimpleUserDefinedLiteralOperators() throws Exception {
+ parseAndCheckBindings();
+ }
+
+ // int integers[] = {
+ // 1,
+ // 1U,
+ // 1L,
+ // 1LL,
+ // 1ULL,
+ // 1suff,
+ // 1_suff,
+ // 0x3003,
+ // 0x3003U,
+ // 0x3003L,
+ // 0x3003LL,
+ // 0x3003ULL,
+ // 0x3003suff,
+ // 0x3003_suff,
+ // 0xabcdef,
+ // 0xABCDEF,
+ // 0Xabcdef,
+ // 0xABCDEF,
+ // 0xABCDEFU,
+ // 0xABCDEFL,
+ // 0xABCDEFULL,
+ // 0xABCDEFsuff,
+ // 0xABCDEF_suff,
+ // 01,
+ // 01U,
+ // 01L,
+ // 07LL,
+ // 04ULL,
+ // 01_suff,
+ // 1ULL << 34,
+ // };
+ public void testIntegerUserDefinedLiterals() throws Exception {
+ parseAndCheckBindings();
+ }
+
+ // double numbers[] = {
+ // 1f,
+ // 1.f,
+ // 1.X,
+ // 1.0x,
+ // 0x01p3,
+ // 0x01p3XX,
+ // 1._X
+ // };
+ public void testDoublesUserDefinedLiterals() throws Exception {
+ parseAndCheckBindings();
+ }
+
+ // char c1 = '0'_suff;
+ // char c2 = '0'suff;
+ // char* c3 = "Hello"_suff;
+ // char* c4 = "Hello"suff;
+ public void testCharStringUserDefinedLiterals() throws Exception {
+ parseAndCheckBindings();
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(unsigned long long i) { return Ret(); }
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(long double i) { return Ret(); }
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s) { return Ret(); }
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s) { return Ret(); }
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(unsigned long long d) { return Ret(); }
+ // bool operator "" _X(const char* s) { return false; }
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(long double d) { return Ret(); }
+ // bool operator "" _X(const char* s) { return false; }
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X;
+ public void testUserDefinedLiteralOperatorTypes3() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+ // auto test = L"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+ // auto test = u"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = U"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3c() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // template<char... Chars> Ret operator "" _X() { return Ret(); }
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes4a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // template<char... Chars> Ret operator "" _X() { return Ret(); }
+ // auto test = 123.123_X;
+ public void testUserDefinedLiteralOperatorTypes4b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123" "123"_X;
+ public void testUserDefinedLiteralConcatenation1a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X "123";
+ public void testUserDefinedLiteralConcatenation1b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = u8"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation2a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = u8"123"_X "123";
+ public void testUserDefinedLiteralConcatenation2b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123" u8"123"_X;
+ public void testUserDefinedLiteralConcatenation2c() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X u8"123";
+ public void testUserDefinedLiteralConcatenation2d() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+ // auto test = L"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation3a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+ // auto test = L"123"_X "123";
+ public void testUserDefinedLiteralConcatenation3b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123" L"123"_X;
+ public void testUserDefinedLiteralConcatenation3c() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X L"123";
+ public void testUserDefinedLiteralConcatenation3d() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+ // auto test = u"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation4a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+ // auto test = u"123"_X "123";
+ public void testUserDefinedLiteralConcatenation4b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123" u"123"_X;
+ public void testUserDefinedLiteralConcatenation4c() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X u"123";
+ public void testUserDefinedLiteralConcatenation4d() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = U"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation5a() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = U"123"_X "123";
+ public void testUserDefinedLiteralConcatenation5b() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123" U"123"_X;
+ public void testUserDefinedLiteralConcatenation5c() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X U"123";
+ public void testUserDefinedLiteralConcatenation5d() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X U"123"_X;
+ public void testUserDefinedLiteralConcatenation6() throws Exception {
+ checkUserDefinedLiteralIsRet(getAboveComment());
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // Ret operator "" _Y(const char* s, unsigned sz) { return Ret(); }
+ // auto test = "123"_X "123"_Y;
+ public void testUserDefinedLiteralBadConcatenation1() throws Exception {
+ IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
+
+ IASTProblem[] problems = tu.getPreprocessorProblems();
+ assertEquals(1, problems.length);
+
+ assertEquals(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, problems[0].getID());
+ }
+
+ // // Test name lacking a space
+ // int operator ""_X(const char* s) { return 0; }
+ public void testUserDefinedLiteralNoWhiteSpace1() throws Exception {
+ IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
+ IASTDeclaration decl = tu.getDeclarations()[0];
+
+ assertTrue(decl instanceof IASTProblemDeclaration);
+ assertEquals(IProblem.SYNTAX_ERROR, ((IASTProblemDeclaration)decl).getProblem().getID());
+ }
+
+ // // Test literals with spaces before the suffix
+ // int operator "" _X(const char* s) { return 0; }
+ // auto a = 1 _X;
+ // auto b = 1.0 _X;
+ // auto c1 = '1' _X;
+ // auto c2 = L'1' _X;
+ // auto c3 = u8'1' _X;
+ // auto c4 = u'1' _X;
+ // auto c5 = U'1' _X;
+ // auto d1 = "1" _X;
+ // auto d2 = L"1" _X;
+ // auto d3 = u8"1" _X;
+ // auto d4 = u"1" _X;
+ // auto d5 = U"1" _X;
+ // auto e1 = "1" _X "2";
+ // auto e2 = L"1" _X "2";
+ // auto e3 = u8"1" _X "2";
+ // auto e4 = u"1" _X "2";
+ // auto e5 = U"1" _X "2";
+ // auto d5 = U"1" _X;
+ public void testUserDefinedLiteralNoWhiteSpace2() throws Exception {
+ IASTTranslationUnit tu = parse(getAboveComment(), CPP, true, false);
+ IASTDeclaration[] decls = tu.getDeclarations();
+
+ for (int i = 1; i < decls.length; i++) {
+ IASTDeclaration decl = decls[i];
+ assertTrue(decl instanceof IASTProblemDeclaration);
+ assertEquals(IProblem.SYNTAX_ERROR, ((IASTProblemDeclaration)decl).getProblem().getID());
+ }
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(unsigned long long i) { return RetB(); }
+ // auto a = 123_X;
+ public void testUserDefinedLiteralResolution1() throws Exception {
+ checkUserDefinedLiteralIsType(getAboveComment(), "RetB");
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(long double i) { return RetB(); }
+ // auto a = 123.123_X;
+ public void testUserDefinedLiteralResolution2() throws Exception {
+ checkUserDefinedLiteralIsType(getAboveComment(), "RetB");
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(const char * c) { return RetB(); }
+ // auto test = 123_X;
+ public void testUserDefinedLiteralResolution3() throws Exception {
+ BindingAssertionHelper bh = getAssertionHelper();
+ ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
+ assertTrue(test.getType() instanceof IProblemType); // resolution is ambiguous
+ }
}
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
assertEquals(17, problems.length);
int i= 0;
assertEquals(IProblem.SCANNER_BAD_OCTAL_FORMAT, problems[i].getID());
- assertEquals(IProblem.SCANNER_BAD_DECIMAL_FORMAT, problems[++i].getID());
- assertEquals(IProblem.SCANNER_BAD_HEX_FORMAT, problems[++i].getID());
- assertEquals(IProblem.SCANNER_BAD_HEX_FORMAT, problems[++i].getID());
+ assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
+ assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
+ assertEquals(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, problems[++i].getID());
assertEquals(IProblem.SCANNER_DIVIDE_BY_ZERO, problems[++i].getID());
assertEquals(IProblem.SCANNER_MISSING_R_PAREN, problems[++i].getID());
assertEquals(IProblem.SCANNER_MISSING_R_PAREN, problems[++i].getID());
/*******************************************************************************
- * Copyright (c) 2004, 2008 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Contributors:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scanner;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken;
+import org.eclipse.cdt.core.parser.ParserLanguage;
import junit.framework.TestSuite;
// #define tp(x,y) #x##y
// tp(a, );
+ // tp(a,_b);
+ public void testStringifyAndPasteCPP() throws Exception {
+ initializeScanner(getAboveComment(), ParserLanguage.CPP);
+ validateString("a");
+ validateToken(IToken.tSEMI);
+
+ validateUserDefinedLiteralString("a", "_b");
+ validateToken(IToken.tSEMI);
+ validateEOF();
+ validateProblemCount(0);
+ }
+
+ // #define tp(x,y) #x##y
+ // tp(a, );
// tp(a,b);
- public void testStringifyAndPaste() throws Exception {
- initializeScanner();
+ public void testStringifyAndPasteC() throws Exception {
+ initializeScanner(getAboveComment(), ParserLanguage.C);
validateString("a");
validateToken(IToken.tSEMI);
validateToken(IToken.tSEMI);
validateEOF();
validateProblemCount(0);
+ }
+ public void testBadBinaryNumbersC() throws Exception {
String badbinary = "{0b012, 0b01b, 0b1111e01, 0b1111p10, 0b10010.10010}";
- initializeScanner(badbinary);
+ initializeScanner(badbinary, ParserLanguage.C);
fullyTokenize();
validateProblemCount(5);
- for (int i = 0; i < 5; i++) {
- validateProblem(i, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
- }
+ validateProblem(0, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
+ validateProblem(1, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "b");
+ validateProblem(2, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
+ validateProblem(3, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "p10");
+ validateProblem(4, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
+ }
+
+ public void testBadBinaryNumbersCPP() throws Exception {
+ // First, third, and fifth are invalid in c++11.
+ String badbinary = "{0b012, 0b01b, 0b1111e01, 0b1111p10, 0b10010.10010}";
+ initializeScanner(badbinary);
+ fullyTokenize();
+ validateProblemCount(3);
+ validateProblem(0, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
+ validateProblem(1, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
+ validateProblem(2, IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b");
+ }
+
+ // #if 123ASDF
+ // #endif
+ // #if 0xU
+ // #endif
+ public void testUDLInPP() throws Exception {
+ initializeScanner();
+ validateEOF();
+ validateProblemCount(2);
+ validateProblem(0, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "ASDF");
+ validateProblem(1, IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, "xU");
}
}
/*******************************************************************************
- * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
import java.io.IOException;
-import junit.framework.ComparisonFailure;
-
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
+import junit.framework.ComparisonFailure;
+
public abstract class PreprocessorTestsBase extends BaseTestCase {
private static final IParserLogService NULL_LOG = new NullLogService();
protected CPreprocessor fScanner;
validateToken(IToken.tUTF32STRING, "U\"" + expectedImage + "\"");
}
+ protected void validateUserDefinedLiteralString(String expectedImage, String expectedSuffix) throws Exception {
+ validateToken(IToken.tUSER_DEFINED_STRING_LITERAL, "\"" + expectedImage + "\"" + expectedSuffix);
+ }
+
protected void validateChar(String expectedImage) throws Exception {
validateToken(IToken.tCHAR, "'" + expectedImage + "'");
}
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
+import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IPointerType;
+import org.eclipse.cdt.core.dom.ast.IProblemType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
+import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.core.runtime.CoreException;
assertNotNull(numericalValue);
assertEquals(i, numericalValue.longValue());
}
-
+
+ private void assertUserDefinedLiteralType(String retName) {
+ ICPPVariable v= getBindingFromFirstIdentifier("test =");
+ assertEquals(retName, ASTTypeUtil.getType(v.getType()));
+ }
// namespace ns { class A; enum E {E1}; typedef int T; }
//
assertEquals(1, ors.length);
assertEquals(ors[0], m1);
}
+
+ // class Ret {};
+ // Ret operator "" _X(unsigned long long i) { return Ret(); }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(long double i) { return Ret(); }
+
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s) { return Ret(); }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s) { return Ret(); }
+
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(unsigned long long d) { return Ret(); }
+ // bool operator "" _X(const char* s) { return false; }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes1b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(long double d) { return Ret(); }
+ // bool operator "" _X(const char* s) { return false; }
+
+ // auto test = 12.3_X;
+ public void testUserDefinedLiteralOperatorTypes2b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X;
+ public void testUserDefinedLiteralOperatorTypes3() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = L"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = u"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = U"123"_X;
+ public void testUserDefinedLiteralOperatorTypes3c() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // template<char... Chars> Ret operator "" _X() { return Ret(); }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralOperatorTypes4a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // template<char... Chars> Ret operator "" _X() { return Ret(); }
+
+ // auto test = 123.123_X;
+ public void testUserDefinedLiteralOperatorTypes4b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123" "123"_X;
+ public void testUserDefinedLiteralConcatenation1a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X "123";
+ public void testUserDefinedLiteralConcatenation1b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = u8"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation2a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = u8"123"_X "123";
+ public void testUserDefinedLiteralConcatenation2b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123" u8"123"_X;
+ public void testUserDefinedLiteralConcatenation2c() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X u8"123";
+ public void testUserDefinedLiteralConcatenation2d() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = L"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation3a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = L"123"_X "123";
+ public void testUserDefinedLiteralConcatenation3b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123" L"123"_X;
+ public void testUserDefinedLiteralConcatenation3c() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const wchar_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X L"123";
+ public void testUserDefinedLiteralConcatenation3d() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = u"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation4a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = u"123"_X "123";
+ public void testUserDefinedLiteralConcatenation4b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123" u"123"_X;
+ public void testUserDefinedLiteralConcatenation4c() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char16_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X u"123";
+ public void testUserDefinedLiteralConcatenation4d() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = U"123" "123"_X;
+ public void testUserDefinedLiteralConcatenation5a() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = U"123"_X "123";
+ public void testUserDefinedLiteralConcatenation5b() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123" U"123"_X;
+ public void testUserDefinedLiteralConcatenation5c() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X U"123";
+ public void testUserDefinedLiteralConcatenation5d() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char32_t* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X U"123"_X;
+ public void testUserDefinedLiteralConcatenation6() throws Exception {
+ assertUserDefinedLiteralType("Ret");
+ }
+
+ // class Ret {};
+ // Ret operator "" _X(const char* s, unsigned sz) { return Ret(); }
+ // Ret operator "" _Y(const char* s, unsigned sz) { return Ret(); }
+
+ // auto test = "123"_X "123"_Y;
+ public void testUserDefinedLiteralBadConcat1() throws Exception {
+ IASTProblem[] problems = strategy.getAst(0).getPreprocessorProblems();
+ assertEquals(1, problems.length);
+ assertEquals(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, problems[0].getID());
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(unsigned long long i) { return RetB(); }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralResolution1() throws Exception {
+ assertUserDefinedLiteralType("RetB");
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(long double i) { return RetB(); }
+
+ // auto test = 123.123_X;
+ public void testUserDefinedLiteralResolution2() throws Exception {
+ assertUserDefinedLiteralType("RetB");
+ }
+
+ // class RetA {};
+ // class RetB {};
+ // template<char... Chars> RetA operator "" _X() { return RetA(); }
+ // RetB operator "" _X(const char * c) { return RetB(); }
+
+ // auto test = 123_X;
+ public void testUserDefinedLiteralResolution3() throws Exception {
+ ICPPVariable v= getBindingFromFirstIdentifier("test");
+ assertTrue(v.getType() instanceof IProblemType);
+ }
}
/*******************************************************************************
- * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser;
return false;
}
+ /**
+ * {@inheritDoc}
+ * @since 5.11
+ */
+ @Override
+ public boolean supportUserDefinedLiterals() {
+ return false;
+ }
+
@Override
public CharArrayIntMap getAdditionalPreprocessorKeywords() {
return fAddPreprocessorKeywords;
/*******************************************************************************
- * Copyright (c) 2004, 2011 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser;
public char[] supportAdditionalNumericLiteralSuffixes() {
return "ij".toCharArray(); //$NON-NLS-1$
}
-
+
+ /**
+ * @since 5.10
+ */
+ @Override
+ public boolean supportUserDefinedLiterals() {
+ return false;
+ }
+
/**
* @deprecated simply derive from this class and use {@link #addMacro(String, String)} to
* add additional macros.
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* @since 5.5
*/
public boolean supportRawStringLiterals();
+
+ /**
+ * Support for User Defined Literals such as 123_suffix
+ * @since 5.11
+ */
+ public boolean supportUserDefinedLiterals();
}
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser.cpp;
public boolean supportFunctionStyleAssembler() {
return false;
}
-
+
+ /**
+ * {@inheritDoc}
+ * @since 5.11
+ */
+ @Override
+ public boolean supportUserDefinedLiterals() {
+ return true;
+ }
+
+ /*
+ * @see org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration#getBuiltinBindingsProvider()
+ */
@Override
public IBuiltinBindingsProvider getBuiltinBindingsProvider() {
return new GCCBuiltinSymbolProvider(ParserLanguage.CPP, supportGCCOtherBuiltinSymbols());
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser.cpp;
public boolean supportRawStringLiterals() {
return true;
}
+
+ /**
+ * User Defined Literals
+ * @since 5.10
+ */
+ @Override
+ public boolean supportUserDefinedLiterals() {
+ return true;
+ }
}
/*******************************************************************************
- * Copyright (c) 2002, 2009 IBM Corporation and others.
+ * Copyright (c) 2002, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* @since 5.1
*/
public boolean supportFunctionStyleAssembler();
+
+ /**
+ * Support user-defined literal expressions:
+ * (char_expr | string_expr | int_expr | float_expr) ud-suffix
+ * @since 5.11
+ */
+ public boolean supportUserDefinedLiterals();
/**
* Additional variants of context-sensitive keywords.
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* Contributors:
* John Camelon (IBM Corporation) - initial API and implementation
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.core.parser;
* @since 5.1
*/
public final static int SCANNER_BAD_BINARY_FORMAT = SCANNER_RELATED | 0x00F;
-
+
+ /**
+ * Invalid suffix on constant
+ * @since 5.11
+ */
+ public final static int SCANNER_CONSTANT_WITH_BAD_SUFFIX = SCANNER_RELATED | 0x010;
+
+ /**
+ * Invalid prefix on float
+ * @since 5.11
+ */
+ public final static int SCANNER_FLOAT_WITH_BAD_PREFIX = SCANNER_RELATED | 0x011;
+
// Preprocessor
/**
* #error encountered by Preprocessor.
* macro argument "..." encountered without the required ')' i.e. must be last argument if used
* Required attributes: none
*/
- public final static int PREPROCESSOR_MISSING_RPAREN_PARMLIST = PREPROCESSOR_RELATED | 0x00C;
+ public final static int PREPROCESSOR_MISSING_RPAREN_PARMLIST = PREPROCESSOR_RELATED | 0x00C;
/**
* __VA_ARGS__ encountered in macro definition without the required '...' parameter
* Required attributes: none
- */
+ */
public final static int PREPROCESSOR_INVALID_VA_ARGS = PREPROCESSOR_RELATED | 0x00D;
/**
public final static int PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH= PREPROCESSOR_RELATED | 0x00F;
/**
+ * During concatenation of string literals, at least two were found with more than one type of UDL suffix.
+ * @since 5.11
+ */
+ public final static int PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION = PREPROCESSOR_RELATED | 0x010;
+
+ /*
* Syntax error, detected by the parser.
*/
public final static int SYNTAX_ERROR = SYNTAX_RELATED | 0x001;
/*******************************************************************************
- * Copyright (c) 2003, 2013 IBM Corporation and others.
+ * Copyright (c) 2003, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*/
@Deprecated
public void setScanComments(boolean val);
+
+ /**
+ * Returns a list of additional (compiler specific) suffixes which can
+ * be placed on numbers. e.g. 'u' 'l' -> 1l or 1u.
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public char[] getAdditionalNumericLiteralSuffixes();
}
int tLSTRING = 131;
/** @since 5.1 */ int tUTF16STRING = 5000;
/** @since 5.1 */ int tUTF32STRING = 5001;
+ /** @since 5.11 */ int tUSER_DEFINED_STRING_LITERAL = 51002;
int tCHAR = 132;
int tLCHAR = 133;
/** @since 5.1 */ int tUTF16CHAR = 5002;
/** @since 5.1 */ int tUTF32CHAR = 5003;
+ /** @since 5.11 */ int tUSER_DEFINED_CHAR_LITERAL = 51003;
/** @since 5.10 */ int t__Alignas = 51000;
/** @since 5.10 */ int t__Alignof = 51001;
/*******************************************************************************
- * Copyright (c) 2004, 2011 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
errorMessages.put(new Integer(PREPROCESSOR_MISSING_RPAREN_PARMLIST),
ParserMessages.getString("ScannerProblemFactory.error.preproc.missingRParen")); //$NON-NLS-1$
errorMessages.put(new Integer(PREPROCESSOR_INVALID_VA_ARGS),
- ParserMessages.getString("ScannerProblemFactory.error.preproc.invalidVaArgs")); //$NON-NLS-1$
+ ParserMessages.getString("ScannerProblemFactory.error.preproc.invalidVaArgs")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_INVALID_ESCAPECHAR),
ParserMessages.getString("ScannerProblemFactory.error.scanner.invalidEscapeChar")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_UNBOUNDED_STRING),
ParserMessages.getString("ScannerProblemFactory.error.scanner.unexpectedEOF")); //$NON-NLS-1$
errorMessages.put(new Integer(SCANNER_BAD_CHARACTER),
ParserMessages.getString("ScannerProblemFactory.error.scanner.badCharacter")); //$NON-NLS-1$
+ errorMessages.put(new Integer(SCANNER_CONSTANT_WITH_BAD_SUFFIX),
+ ParserMessages.getString("ScannerProblemFactory.error.scanner.constantWithBadSuffix")); //$NON-NLS-1$
+ errorMessages.put(new Integer(SCANNER_FLOAT_WITH_BAD_PREFIX),
+ ParserMessages.getString("ScannerProblemFactory.error.scanner.floatWithBadPrefix")); //$NON-NLS-1$
+ errorMessages.put(new Integer(PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION),
+ ParserMessages.getString("ScannerProblemFactory.error.preproc.multipleUserDefinedLiteralSuffixesOnStringLiteral")); //$NON-NLS-1$
errorMessages.put(new Integer(SYNTAX_ERROR),
ParserMessages.getString("ParserProblemFactory.error.syntax.syntaxError")); //$NON-NLS-1$
errorMessages.put(new Integer(MISSING_SEMICOLON),
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
+import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
+import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
+import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.Value;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator;
private int fKind;
private char[] fValue = CharArrayUtils.EMPTY;
private int fStringLiteralSize = -1; // Accounting for escape sequences and the null terminator.
+ private char[] fSuffix = CharArrayUtils.EMPTY;
+ private boolean fIsCompilerSuffix = true;
private ICPPEvaluation fEvaluation;
public CPPASTLiteralExpression() {
this.fKind = kind;
this.fValue = value;
}
+
+ public CPPASTLiteralExpression(int kind, char[] value, char[] suffix) {
+ this(kind, value);
+ this.setSuffix(suffix);
+ }
@Override
public CPPASTLiteralExpression copy() {
@Override
public CPPASTLiteralExpression copy(CopyStyle style) {
- CPPASTLiteralExpression copy =
- new CPPASTLiteralExpression(fKind, fValue == null ? null : fValue.clone());
+ CPPASTLiteralExpression copy = new CPPASTLiteralExpression(fKind,
+ fValue == null ? null : fValue.clone(),
+ fSuffix == null ? null : fSuffix.clone());
+ copy.setOffsetAndLength(this);
return copy(copy, style);
}
this.fValue= value;
}
- @Override
+ public char[] getSuffix() {
+ return fSuffix;
+ }
+
+ public void setSuffix(char[] suffix) {
+ this.fSuffix = suffix;
+ }
+
+ public void calculateSuffix() {
+ this.calculateSuffix(CharArrayUtils.EMPTY);
+ }
+
+ /**
+ * Returns the suffix of a user-defined literal integer or float
+ * @param compilerSuffixes
+ */
+ public void calculateSuffix(char[] compilerSuffixes) {
+ try {
+ switch (fKind) {
+ case lk_float_constant:
+ case lk_integer_constant:
+ int udOffset = (fValue[0] == '.' ? afterDecimalPoint(0) : integerLiteral());
+ if (udOffset > 0) {
+ /*
+ * 2.14.8.1
+ * "If a token matches both user-defined-literal and another literal kind, it is treated as the latter"
+ */
+ setSuffix(CharArrayUtils.subarray(fValue, udOffset, -1));
+ for (int i = 0; i < fSuffix.length; i++) {
+ switch (fSuffix[i]) {
+ case 'l': case 'L':
+ case 'u': case 'U':
+ case 'f': case 'F':
+ continue;
+ }
+ for (int j = 0; j < compilerSuffixes.length; j++) {
+ if (fSuffix[i] == compilerSuffixes[j]) {
+ continue;
+ }
+ }
+ fIsCompilerSuffix = false;
+ // Remove the suffix from the value if it's a UDL
+ setValue(CharArrayUtils.subarray(fValue, 0, udOffset));
+ break;
+ }
+ }
+ break;
+ case lk_string_literal:
+ {
+ final int offset = CharArrayUtils.lastIndexOf('"', fValue, CharArrayUtils.indexOf('"', fValue) + 1);
+ if (offset > 0) {
+ setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1));
+ }
+ }
+ break;
+ case lk_char_constant:
+ {
+ final int offset = CharArrayUtils.lastIndexOf('\'', fValue, CharArrayUtils.indexOf('\'', fValue) + 1);
+ if (offset > 0) {
+ setSuffix(CharArrayUtils.subarray(fValue, offset + 1, -1));
+ }
+ }
+ break;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+ }
+
+ @Override
public String toString() {
return new String(fValue);
}
}
return Value.create(fStringLiteralSize);
}
-
- private Kind getCharType() {
- switch (getValue()[0]) {
+
+ private IType getStringType() {
+ if (fSuffix.length > 0) {
+ return getUserDefinedLiteralOperatorType();
+ }
+
+ IType type = new CPPBasicType(getBasicCharKind(), 0, this);
+ type = new CPPQualifierType(type, true, false);
+ return new CPPArrayType(type, getStringLiteralSize());
+ }
+
+ private IType getCharType() {
+ return fSuffix.length > 0 ? getUserDefinedLiteralOperatorType() : new CPPBasicType(getBasicCharKind(), 0, this);
+ }
+
+ // 13.5.8
+ private IType getUserDefinedLiteralOperatorType() {
+ IType ret = new ProblemType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
+
+ try {
+ IBinding func = CPPSemantics.findUserDefinedLiteralOperator(this);
+ if (func != null && func instanceof ICPPFunction) {
+ ret = ((ICPPFunction) func).getType().getReturnType();
+ }
+ } catch (DOMException e) { /* ignore and return the problem type */ }
+
+ return ret;
+ }
+
+ public char[] getOperatorName() {
+ return CharArrayUtils.concat("operator \"\"".toCharArray(), fSuffix); //$NON-NLS-1$
+ }
+
+ public Kind getBasicCharKind() {
+ switch (fValue[0]) {
case 'L':
return Kind.eWChar;
case 'u':
default:
return Kind.eChar;
}
- }
+ }
private IType classifyTypeOfFloatLiteral() {
- final char[] lit= getValue();
+ final char[] lit= fSuffix;
final int len= lit.length;
Kind kind= Kind.eDouble;
int flags= 0;
if (len > 0) {
- switch (lit[len - 1]) {
- case 'f': case 'F':
- kind= Kind.eFloat;
- break;
- case 'l': case 'L':
- flags |= IBasicType.IS_LONG;
- break;
+ if (fIsCompilerSuffix) {
+ switch (lit[len - 1]) {
+ case 'f': case 'F':
+ kind= Kind.eFloat;
+ break;
+ case 'l': case 'L':
+ flags |= IBasicType.IS_LONG;
+ break;
+ }
+ } else {
+ return getUserDefinedLiteralOperatorType();
}
}
return new CPPBasicType(kind, flags, this);
private IType classifyTypeOfIntLiteral() {
int makelong= 0;
boolean unsigned= false;
+ final char[] lit= fSuffix;
+ int flags= 0;
+
+ if (fIsCompilerSuffix) {
+ for (int i= lit.length - 1; i >= 0; i--) {
+ final char c= lit[i];
+ if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
+ break;
+ }
+ switch (c) {
+ case 'u':
+ case 'U':
+ unsigned = true;
+ break;
+ case 'l':
+ case 'L':
+ makelong++;
+ break;
+ }
+ }
- final char[] lit= getValue();
- for (int i= lit.length - 1; i >= 0; i--) {
- final char c= lit[i];
- if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
- break;
+ if (unsigned) {
+ flags |= IBasicType.IS_UNSIGNED;
}
- switch (c) {
- case 'u':
- case 'U':
- unsigned = true;
- break;
- case 'l':
- case 'L':
- makelong++;
+
+ if (makelong > 1) {
+ flags |= IBasicType.IS_LONG_LONG;
+ } else if (makelong == 1) {
+ flags |= IBasicType.IS_LONG;
+ }
+ } else if (lit.length > 0) {
+ return getUserDefinedLiteralOperatorType();
+ }
+ return new CPPBasicType(Kind.eInt, flags, this);
+ }
+
+ private int integerLiteral() {
+ int i = 0;
+ char c = fValue[i++];
+
+ if (c == '0' && i < fValue.length) {
+ // Probably octal/hex/binary
+ c = fValue[i];
+ switch ((c | 0x20)) {
+ case 'x':
+ return probablyHex(i);
+ case 'b':
+ return probablyBinary(i);
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ /* octal-literal:
+ * 0
+ * octal-literal octal-digit
+ */
+ while (isOctal(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
break;
+ case '.':
+ return afterDecimalPoint(i);
+ }
+ /*
+ * If there is an 8 or 9, then we have a malformed octal
+ */
+ if (c == '8' || c == '9') {
+ // eat remaining numbers
+ c = fValue[i];
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+ return i;
+ }
+ } else if (Character.isDigit(c)) {
+ /* decimal-literal :
+ * nonzero-digit (c has to be this to get into this else)
+ * decimal-literal digit
+ */
+ c = fValue[i];
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+
+ if (c == '.') {
+ return afterDecimalPoint(i);
+ } else if ((c | 0x20) == 'e') {
+ return exponentPart(i);
}
+ } else {
+ // Somehow we got called and there wasn't a digit
+ // Shouldn't get here
+ assert false;
}
-
- int flags= 0;
- if (unsigned) {
- flags |= IBasicType.IS_UNSIGNED;
+
+ return i;
+ }
+
+ /*
+ * Called with the expectation that fValue[i] == '.'
+ */
+ private int afterDecimalPoint(int i) {
+ char c = fValue[++i];
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[++i];
}
- if (makelong > 1) {
- flags |= IBasicType.IS_LONG_LONG;
- } else if (makelong == 1) {
- flags |= IBasicType.IS_LONG;
- }
- return new CPPBasicType(Kind.eInt, flags, this);
+ if ((c | 0x20) == 'e') {
+ return exponentPart(i);
+ }
+
+ return i;
+ }
+
+ /*
+ * Called with the expectation that c == 'e'
+ */
+ private int exponentPart(int i) {
+ char c = fValue[++i];
+
+ // optional '+' or '-'
+ if (c == '+' || c == '-') {
+ c = fValue[++i];
+ }
+
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+ // If there were no digits following the 'e' then we have
+ // D.De or .De which is a UDL on a double
+
+ return i--;
+ }
+
+ // GCC's binary constant notation
+ private int probablyBinary(int i) {
+ char c = fValue[++i];
+
+ if (c == '1' || c == '0') {
+ while (c == '1' || c == '0' && i < fValue.length) {
+ c = fValue[i++];
+ }
+ if (Character.isDigit(c)) {
+ // UDL can't begin with digit, so this is a malformed binary
+ return -1;
+ } else if (c == '.') {
+ // no such thing as binary floating point
+ c = fValue[++i];
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[i++];
+ }
+ }
+ } else {
+ // Here we have 0b or 0B
+ return i - 1;
+ }
+ return i;
+ }
+
+ private int probablyHex(int i) {
+ /* hexadecimal-literal
+ * 0x hexadecimal-digit
+ * 0X hexadecimal-digit
+ * hexadecimal-literal hexadecimal-digit
+ */
+ char c = fValue[++i];
+ if (isHexDigit(c)) {
+ while (isHexDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+ if (c == '.') {
+ // Could be GCC's hex float
+ return hexFloatAfterDecimal(i);
+ } else if ((c | 0x20) == 'p') {
+ return hexFloatExponent(i);
+ }
+ } else {
+ return i - 1;
+ }
+
+ return i;
+ }
+
+ // Assumes fValue[i] == '.'
+ private int hexFloatAfterDecimal(int i) {
+ // 0xHHH.
+ char c = fValue[++i];
+ if (isHexDigit(c)) {
+ while (isHexDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+
+ if ((c | 0x20) == 'p') {
+ return hexFloatExponent(i);
+ } else {
+ // The parser is very confused at this point
+ // as the expression is 0x1.f
+ return -1;
+ }
+ }
+
+ // Probably shouldn't be able to get here
+ // we have 0xHHH.
+ return -1;
+ }
+
+ // Assumes image[i] == 'p'
+ private int hexFloatExponent(int i) {
+ // 0xHH.HH[pP][-+]?DDDD
+ char c = fValue[++i];
+
+ if (c == '-' || c == '+') {
+ c = fValue[++i];
+ }
+
+ if (Character.isDigit(c)) {
+ while (Character.isDigit(c) && i < fValue.length) {
+ c = fValue[++i];
+ }
+ } else {
+ return i - 1;
+ }
+ return i;
+ }
+
+ private boolean isHexDigit(char c) {
+ c |= 0x20;
+ return ((c <= 'f' && c >= 'a') || (c <= '9' && c >= '0'));
+ }
+
+ private boolean isOctal(final char c) {
+ return c >= '0' && c <= '7';
}
/**
case lk_false:
return EVAL_FALSE;
case lk_char_constant:
- return new EvalFixed(new CPPBasicType(getCharType(), 0, this), PRVALUE, createCharValue());
- case lk_float_constant:
+ return new EvalFixed(getCharType(), PRVALUE, createCharValue());
+ case lk_float_constant:
return new EvalFixed(classifyTypeOfFloatLiteral(), PRVALUE, Value.UNKNOWN);
- case lk_integer_constant:
+ case lk_integer_constant:
return new EvalFixed(classifyTypeOfIntLiteral(), PRVALUE, createIntValue());
case lk_string_literal:
- IType type = new CPPBasicType(getCharType(), 0, this);
- type = new CPPQualifierType(type, true, false);
- return new EvalFixed(new CPPArrayType(type, getStringLiteralSize()), LVALUE, Value.UNKNOWN);
+ return new EvalFixed(getStringType(), LVALUE, Value.UNKNOWN);
case lk_nullptr:
return EVAL_NULL_PTR;
}
case eVoid:
return t_void;
case eNullPtr:
- // Null pointer type cannot be expressed wit ha simple decl specifier.
+ // Null pointer type cannot be expressed with a simple decl specifier.
break;
}
return t_unspecified;
public static final CPPBasicType UNSIGNED_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED);
public static final CPPBasicType UNSIGNED_LONG_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG_LONG | IBasicType.IS_UNSIGNED);
public static final CPPBasicType UNSIGNED_INT128 = new CPPBasicType(Kind.eInt128, IBasicType.IS_UNSIGNED);
+ public static final CPPBasicType CHAR = new CPPBasicType(Kind.eChar, 0);
private static final int FROM_STRING_LITERAL = 1 << 31;
* Thomas Corbat (IFS)
* Anders Dahlberg (Ericsson) - bug 84144
* Nathan Ridge
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
private final boolean allowCPPRestrict;
private final boolean supportExtendedTemplateSyntax;
private final boolean supportAutoTypeSpecifier;
+ private final boolean supportUserDefinedLiterals;
private final IIndex index;
protected ICPPASTTranslationUnit translationUnit;
private int functionBodyCount;
private char[] currentClassName;
+ private char[] additionalNumericalSuffixes;
private final ICPPNodeFactory nodeFactory;
private TemplateIdStrategy fTemplateParameterListStrategy;
supportFunctionStyleAsm= config.supportFunctionStyleAssembler();
functionCallCanBeLValue= true;
supportAutoTypeSpecifier= true;
+ supportUserDefinedLiterals= config.supportUserDefinedLiterals();
this.index= index;
this.nodeFactory = CPPNodeFactory.getDefault();
scanner.setSplitShiftROperator(true);
fContextSensitiveTokens = createContextSensitiveTokenMap(config);
+ additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes();
}
private Map<String, ContextSensitiveTokenType> createContextSensitiveTokenMap(
endOffset= consume(IToken.tGT_in_SHIFTR).getEndOffset();
op= OverloadableOperator.SHIFTR;
break;
+ case IToken.tSTRING: // User defined literal T operator "" SUFFIX
+ IToken strOp = consume();
+
+ // Should be an empty string
+ if (strOp.getLength() == 2) {
+ endOffset = strOp.getEndOffset();
+
+ IToken ident = consume(IToken.tIDENTIFIER);
+
+ // Make sure there is at least one white space
+ if (ident.getOffset() <= endOffset) {
+ break;
+ }
+
+ char[] operatorName = CharArrayUtils.concat(firstToken.getCharImage(), " ".toCharArray()); //$NON-NLS-1$
+ operatorName = CharArrayUtils.concat(operatorName, strOp.getCharImage());
+ operatorName = CharArrayUtils.concat(operatorName, ident.getCharImage());
+
+ IASTName name = nodeFactory.newOperatorName(operatorName);
+ setRange(name, firstToken.getOffset(), ident.getEndOffset());
+ return name;
+ }
+ break;
default:
op= OverloadableOperator.valueOf(LA(1));
if (op != null) {
protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken t = null;
IASTLiteralExpression literalExpr = null;
+ IASTLiteralExpression literalExprWithRange = null;
switch (LT(1)) {
case IToken.tINTEGER:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage());
- return setRange(literalExpr, t.getOffset(), t.getEndOffset());
+ literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
+ ((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes);
+ break;
case IToken.tFLOATINGPT:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage());
- return setRange(literalExpr, t.getOffset(), t.getEndOffset());
+ literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
+ ((CPPASTLiteralExpression) literalExpr).calculateSuffix(additionalNumericalSuffixes);
+ break;
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
- return stringLiteral();
+ case IToken.tUSER_DEFINED_STRING_LITERAL:
+ literalExprWithRange = stringLiteral();
+ if (supportUserDefinedLiterals) {
+ ((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix();
+ }
+ break;
case IToken.tCHAR:
case IToken.tLCHAR:
case IToken.tUTF16CHAR:
case IToken.tUTF32CHAR:
- t = consume();
- literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_char_constant, t.getImage());
- return setRange(literalExpr, t.getOffset(), t.getEndOffset());
- case IToken.t_false:
+ case IToken.tUSER_DEFINED_CHAR_LITERAL:
+ t = consume();
+ literalExpr = nodeFactory.newLiteralExpression(
+ IASTLiteralExpression.lk_char_constant, t.getImage());
+ literalExprWithRange = setRange(literalExpr, t.getOffset(), t.getEndOffset());
+ if (supportUserDefinedLiterals) {
+ ((CPPASTLiteralExpression) literalExprWithRange).calculateSuffix();
+ }
+ break;
+ case IToken.t_false:
t = consume();
literalExpr = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_false, t.getImage());
return setRange(literalExpr, t.getOffset(), t.getEndOffset());
throwBacktrack(startingOffset, la.getLength());
return null;
}
+
+ if (supportUserDefinedLiterals) {
+ IToken la = LA(1);
+ int offset = ((ASTNode) literalExprWithRange).getOffset();
+ int length = ((ASTNode) literalExprWithRange).getLength();
+ if (la.getType() == IToken.tIDENTIFIER) {
+ if ((offset + length) != la.getOffset()) {
+ return literalExprWithRange;
+ }
+ IToken opName = consume(IToken.tIDENTIFIER);
+ ((CPPASTLiteralExpression) literalExprWithRange).setSuffix(opName.getCharImage());
+ setRange(literalExprWithRange, offset, opName.getEndOffset());
+ }
+ }
+
+ return literalExprWithRange;
}
private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, BacktrackException {
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
+ case IToken.tUSER_DEFINED_STRING_LITERAL:
break;
default:
throwBacktrack(LA(1));
* Mike Kucera (IBM)
* Thomas Corbat (IFS)
* Nathan Ridge
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
+import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ARRAY;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceScope;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass;
return function;
}
+
+ /**
+ * Given a LiteralExpression with a user-defined literal suffix,
+ * finds the corresponding defined operator.
+ * Tries to implement 2.14.8.(2-10)
+ * @param exp <code>IASTLiteralExpression</code> which has a user-defined literal suffix
+ * @return CPPFunction or null
+ * @throws DOMException
+ */
+ public static IBinding findUserDefinedLiteralOperator(IASTLiteralExpression exp) throws DOMException {
+ IBinding ret = null;
+ /*
+ * 2.14.8.2
+ * Let `IASTLiteralExpression exp` = L
+ * Let `exp.getSuffix()` = X
+ * Let `bindings` = S
+ * A user-defined-literal is treated as a call to a literal operator or
+ * literal operator template (13.5.8). To determine the form of this
+ * call for a given user-defined-literal L with ud-suffix X, the
+ * literal-operator-id whose literal suffix identifier is X is looked up
+ * in the context of L using the rules for unqualified name lookup (3.4.1).
+ * Let S be the set of declarations found by this lookup.
+ * S shall not be empty.
+ *
+ */
+ int kind = exp.getKind();
+ IBinding[] bindings = findBindings(exp.getTranslationUnit().getScope(), ((CPPASTLiteralExpression) exp).getOperatorName(), false);
+ ICPPFunction[] funcs = new ICPPFunction[bindings.length];
+ ICPPFunctionTemplate[] tplFunctions = new ICPPFunctionTemplate[bindings.length];
+ LookupData data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
+
+ int i = 0, j = 0;
+ for (IBinding binding : bindings) {
+ if (binding instanceof ICPPFunction || binding instanceof ICPPFunctionTemplate) {
+ funcs[i++] = (ICPPFunction) binding;
+ if (binding instanceof ICPPFunctionTemplate) {
+ tplFunctions[j++] = (ICPPFunctionTemplate) binding;
+ }
+ }
+ }
+
+ funcs = ArrayUtil.trim(funcs, i);
+ tplFunctions = ArrayUtil.trim(tplFunctions, j);
+
+ if (funcs.length == 0) {
+ // S shall not be empty
+ return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_INVALID_TYPE);
+ }
+
+ if (kind == IASTLiteralExpression.lk_integer_constant || kind == IASTLiteralExpression.lk_float_constant) {
+ if (kind == IASTLiteralExpression.lk_integer_constant) {
+ /*
+ * 2.14.8.3
+ * Let `exp.getValue()` = n
+ * If L is a user-defined-integer-literal, let n be the literal
+ * without its ud-suffix. If S contains a literal operator with
+ * parameter type unsigned long long, then use operator "" X(n ULL)
+ */
+ CPPBasicType t = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG, exp);
+ data.setFunctionArguments(false, createArgForType(exp, t));
+ ret = resolveFunction(data, funcs, true);
+ if (ret != null && !(ret instanceof ProblemBinding)) {
+ return ret;
+ }
+ } else if (kind == IASTLiteralExpression.lk_float_constant) {
+ /*
+ * 2.14.8.4
+ * Let `exp.getValue()` = f
+ * If L is a user-defined-floating-literal, let f be the literal
+ * without its ud-suffix. If S contains a literal operator with
+ * parameter type long double, then use operator "" X(f L)
+ */
+ CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp);
+ data.setFunctionArguments(false, createArgForType(exp, t));
+ ret = resolveFunction(data, funcs, true);
+ if (ret != null && !(ret instanceof ProblemBinding)) {
+ return ret;
+ }
+ }
+
+ /*
+ * 2.14.8.3 (cont.), 2.14.8.4 (cont.)
+ * Otherwise, S shall contain a raw literal operator or a literal
+ * operator template but not both.
+ */
+ // Raw literal operator `operator "" _op(const char * c)`
+ CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false);
+ data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
+ data.setFunctionArguments(false, createArgForType(exp, charArray));
+ ret = resolveFunction(data, funcs, true);
+
+ //
+ char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator
+
+ // The string literal is passed to the operator as chars:
+ // "literal"_op -> operator "" _op<'l', 'i', 't', 'e', 'r', 'a', 'l'>();
+ ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length];
+ for (int k = 0; k < stringLiteral.length; k++) {
+ args[k] = new CPPTemplateNonTypeArgument(new EvalFixed(CPPBasicType.CHAR, PRVALUE, Value.create(stringLiteral[k])), exp);
+ }
+
+ data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp);
+ IBinding litTpl = resolveFunction(data, tplFunctions, true);
+
+ // Do we have valid template and non-template bindings?
+ if (ret != null && litTpl != null) {
+ if (!(ret instanceof IProblemBinding) && litTpl instanceof ICPPFunctionInstance) {
+ // Ambiguity? It has two valid options, and the spec says it shouldn't
+ return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, tplFunctions);
+ }
+
+ if ((ret instanceof IProblemBinding) && litTpl instanceof ICPPFunctionInstance) {
+ // Only the template binding is valid
+ ret = litTpl;
+ }
+ }
+ else if (ret == null) {
+ // Couldn't find a valid operator
+ return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_INVALID_TYPE);
+ }
+ } else if (kind == IASTLiteralExpression.lk_string_literal) {
+ /*
+ * 2.14.8.5
+ * If L is a user-defined-string-literal, let str be the literal
+ * without its ud-suffix and let len be the number of code units in
+ * str (i.e., its length excluding the terminating null character).
+ * L is treated as operator "" X(str, len)
+ */
+ CPPPointerType strType = new CPPPointerType(new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null), true, false, false);
+ IASTInitializerClause[] initializer = new IASTInitializerClause[] {
+ createArgForType(exp, strType),
+ createArgForType(null, CPPBasicType.UNSIGNED_INT)
+ };
+ data.setFunctionArguments(false, initializer);
+ ret = resolveFunction(data, funcs, true);
+ } else if (kind == IASTLiteralExpression.lk_char_constant) {
+ /*
+ * 2.14.8.6
+ * If L is a user-defined-character-literal, let ch be the literal
+ * without its ud-suffix. S shall contain a literal operator whose
+ * only parameter has the type ch and the literal L is treated as a
+ * call operator "" X(ch)
+ */
+ CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp);
+ data.setFunctionArguments(false, createArgForType(exp, t));
+ ret = resolveFunction(data, funcs, true);
+ }
+
+ return ret;
+ }
static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set, IASTNode point) {
targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR);
###############################################################################
-# Copyright (c) 2005, 2014 IBM Corporation and others.
+# Copyright (c) 2005, 2015 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# IBM Rational Software - Initial API and implementation
# Anton Leherbauer (Wind River Systems)
# Markus Schorn (Wind River Systems)
+# Richard Eames
###############################################################################
ScannerProblemFactory.error.preproc.error=#error encountered with text: {0}
ScannerProblemFactory.error.preproc.macroPasting=Invalid use of macro pasting in macro: {0}
ScannerProblemFactory.error.preproc.missingRParen=missing '')'' in parameter list of macro: {0}
ScannerProblemFactory.error.preproc.invalidVaArgs=__VA_ARGS__ can only appear in the expansion of a variadic macro
+ScannerProblemFactory.error.preproc.multipleUserDefinedLiteralSuffixesOnStringLiteral=Multiple user-defined suffixes found when concatenating string literals
ScannerProblemFactory.error.scanner.invalidEscapeChar=Invalid escape character encountered
ScannerProblemFactory.error.scanner.unboundedString=Unbounded string encountered
ScannerProblemFactory.error.scanner.badConditionalExpression=Bad conditional expression
ScannerProblemFactory.error.scanner.unexpectedEOF=Unexpected End Of File encountered
ScannerProblemFactory.error.scanner.badCharacter=Bad character sequence encountered: {0}
+ScannerProblemFactory.error.scanner.constantWithBadSuffix=Constant "{0}" has an invalid suffix
+ScannerProblemFactory.error.scanner.floatWithBadPrefix=Floating constant "{0}" has an invalid prefix
ParserProblemFactory.error.syntax.syntaxError=Syntax error
ParserProblemFactory.error.syntax.missingSemicolon=Missing ';'
/*******************************************************************************
- * Copyright (c) 2004, 2013 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Marc-Andre Laperle (Ericsson)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
fLexOptions.fSupportSlashPercentComments= configuration.supportSlashPercentComments();
fLexOptions.fSupportUTFLiterals = configuration.supportUTFLiterals();
fLexOptions.fSupportRawStringLiterals = configuration.supportRawStringLiterals();
+ fLexOptions.fSupportUserDefinedLiterals = configuration.supportUserDefinedLiterals();
if (info instanceof ExtendedScannerInfo)
fLexOptions.fIncludeExportPatterns = ((ExtendedScannerInfo) info).getIncludeExportPatterns();
fLocationMap= new LocationMap(fLexOptions);
public ILocationResolver getLocationResolver() {
return fLocationMap;
}
-
+
+ /**
+ * @see IScannerExtensionConfiguration#supportAdditionalNumericLiteralSuffixes
+ * @since 5.10
+ */
+ @Override
+ public char[] getAdditionalNumericLiteralSuffixes() {
+ return fAdditionalNumericLiteralSuffixes;
+ }
+
private void configureKeywords(ParserLanguage language, IScannerExtensionConfiguration configuration) {
Keywords.addKeywordsPreprocessor(fPPKeywords);
if (language == ParserLanguage.C) {
t.setNext(null);
return t;
}
-
- try {
+ try {
t= internalFetchToken(fRootContext, CHECK_NUMBERS | REPORT_SIGNIFICANT_MACROS | IGNORE_UNDEFINED_SIGNIFICANT_MACROS, false);
} catch (OffsetLimitReachedException e) {
fHandledCompletion= true;
throw e;
}
- final int offset= fLocationMap.getSequenceNumberForOffset(t.getOffset());
+ final int offset= fLocationMap.getSequenceNumberForOffset(t.getOffset());
final int endOffset= fLocationMap.getSequenceNumberForOffset(t.getEndOffset());
t.setOffset(offset, endOffset);
t.setNext(null);
t.setNext(fPrefetchedTokens);
fPrefetchedTokens= t;
}
-
+
/**
* Returns next token for the parser. String literals are not concatenated. When
* the end is reached tokens with type {@link IToken#tEND_OF_INPUT}.
*/
@Override
public IToken nextToken() throws EndOfFileException {
- if (isCancelled) {
+ if (isCancelled) {
throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED);
}
Token t1= fetchToken();
+ char[] udlSuffix = null;
final int tt1= t1.getType();
switch (tt1) {
case IToken.t_PRAGMA:
handlePragmaOperator(t1);
return nextToken();
-
+ case IToken.tUSER_DEFINED_STRING_LITERAL:
+ udlSuffix = getUserDefinedLiteralSuffix(t1);
+ //$FALL-THROUGH$
case IToken.tSTRING:
case IToken.tLSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
- StringType st = StringType.fromToken(tt1);
+ StringType st = StringType.fromToken(t1);
Token t2;
StringBuilder buf= null;
- int endOffset= 0;
+ int endOffset= t1.getEndOffset();
loop: while (true) {
t2= fetchToken();
final int tt2= t2.getType();
switch (tt2) {
- case IToken.tLSTRING:
+ case IToken.tUSER_DEFINED_STRING_LITERAL:
+ if (udlSuffix == null) {
+ udlSuffix = getUserDefinedLiteralSuffix(t2);
+ } else if (!Arrays.equals(udlSuffix, getUserDefinedLiteralSuffix(t2))) {
+ handleProblem(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION,
+ udlSuffix, t2.getOffset(), endOffset);
+ }
+ //$FALL-THROUGH$
+ case IToken.tLSTRING:
case IToken.tSTRING:
case IToken.tUTF16STRING:
case IToken.tUTF32STRING:
- st = StringType.max(st, StringType.fromToken(tt2));
+ st = StringType.max(st, StringType.fromToken(t2));
if (buf == null) {
buf= new StringBuilder();
appendStringContent(buf, t1);
case IToken.t_PRAGMA:
handlePragmaOperator(t2);
continue loop;
- default:
+ default:
break loop;
}
}
pushbackToken(t2);
if (buf != null) {
char[] prefix = st.getPrefix();
- char[] image= new char[buf.length() + prefix.length + 2];
+ final int imageLength = buf.length() + prefix.length + 2 + (udlSuffix == null ? 0 : udlSuffix.length);
+ char[] image= new char[imageLength];
int off= -1;
+ int tokenType = st.getTokenValue();
for (char c : prefix)
image[++off] = c;
image[++off]= '"';
buf.getChars(0, buf.length(), image, ++off);
- image[image.length - 1]= '"';
- t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image);
+ off += buf.length();
+ image[off]= '"';
+ if (udlSuffix != null) {
+ System.arraycopy(udlSuffix, 0, image, ++off, udlSuffix.length);
+ tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
+ }
+ t1= new TokenWithImage(tokenType, null, t1.getOffset(), endOffset, image);
}
break;
}
if (length > 1) {
- final int diff= image[length - 1] == '"' ? length - start - 1 : length - start;
+ int diff = 0;
+ if (t1.getType() == IToken.tUSER_DEFINED_STRING_LITERAL) {
+ diff = t1.getImage().lastIndexOf('"') - start;
+ } else {
+ diff= image[length - 1] == '"' ? length - start - 1 : length - start;
+ }
if (diff > 0) {
buf.append(image, start, diff);
}
Token internalFetchToken(final ScannerContext uptoEndOfCtx, int options, boolean withinExpansion)
throws OffsetLimitReachedException {
+
+
Token ppToken= fCurrentContext.currentLexerToken();
while (true) {
switch (ppToken.getType()) {
boolean isHex = false;
boolean isOctal = false;
boolean hasDot= false;
+
+ boolean badSuffix = false;
int pos= 0;
if (image.length > 1) {
switch (image[pos]) {
case '0': case'1':
continue;
+ case 'e': case 'E':
+ case '.':
+ handleProblem(IProblem.SCANNER_FLOAT_WITH_BAD_PREFIX, "0b".toCharArray(), number.getOffset(), number.getEndOffset()); //$NON-NLS-1$
+ return;
default:
// 0 and 1 are the only allowed digits for binary integers
// No floating point, exponents etc. are allowed
break loop;
}
}
-
- // check the suffix
- loop: for (; pos < image.length; pos++) {
- final char c= image[pos];
- switch (c) {
- case 'u': case 'U': case 'L': case 'l':
- continue;
- case 'f': case 'F':
- if (isFloat) {
- continue loop;
- }
- }
- for (int i= 0; i < fAdditionalNumericLiteralSuffixes.length; i++) {
- if (fAdditionalNumericLiteralSuffixes[i] == c) {
- continue loop;
- }
- }
- if (isBin) {
- // The check for bin has to come before float, otherwise binary integers
- // with float components get flagged as BAD_FLOATING_POINT
- handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset());
- } else if (isFloat) {
- handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset());
- } else if (isHex) {
- handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset());
- } else if (isOctal) {
- handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
- } else {
- handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
- }
- return;
+ if (pos < image.length) {
+ char c = image[pos];
+ if (Character.isLetter(c) || c == '_') {
+ // check the suffix
+ final int suffixStart = pos;
+ loop: for (; pos < image.length; pos++) {
+ c= image[pos];
+ switch (c) {
+ case 'u': case 'U': case 'L': case 'l':
+ continue;
+ case 'f': case 'F':
+ if (isFloat) {
+ continue loop;
+ }
+
+ //$FALL-THROUGH$
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'g': case 'h': case 'i':
+ case 'j': case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+ case 's': case 't': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'G': case 'H': case 'I':
+ case 'J': case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T':case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '_':
+ if (fLexOptions.fSupportUserDefinedLiterals) {
+ continue loop;
+ }
+ }
+ for (int i= 0; i < fAdditionalNumericLiteralSuffixes.length; i++) {
+ if (fAdditionalNumericLiteralSuffixes[i] == c) {
+ continue loop;
+ } else {
+ badSuffix = true;
+ }
+ }
+
+ if (badSuffix) {
+ char[] suffix = CharArrayUtils.subarray(image, suffixStart, -1);
+ handleProblem(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, suffix, number.getOffset(), number.getEndOffset());
+ return;
+ }
+ }
+ return;
+ }
+ }
+ else {
+ return;
+ }
+
+ if (isBin) {
+ // The check for bin has to come before float, otherwise binary integers
+ // with float components get flagged as BAD_FLOATING_POINT
+ handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset());
+ } else if (isFloat) {
+ handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset());
+ } else if (isHex) {
+ handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset());
+ } else if (isOctal) {
+ handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
+ } else {
+ handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
}
+ return;
+
}
private <T> T findInclusion(final String includeDirective, final boolean quoteInclude,
return true;
}
+ /**
+ * Returns the user-defined suffix of a user-define string literal.
+ *
+ * @param token
+ * @return the suffix of the token, if it exists
+ */
+ private static char[] getUserDefinedLiteralSuffix(IToken token) {
+ if (token.getType() != IToken.tUSER_DEFINED_STRING_LITERAL)
+ throw new IllegalArgumentException();
+
+ char[] image = token.getCharImage();
+ int offset = CharArrayUtils.lastIndexOf('"', image) + 1;
+ if (offset <= 0)
+ throw new IllegalArgumentException();
+ if (offset == image.length)
+ return CharArrayUtils.EMPTY_CHAR_ARRAY;
+ return CharArrayUtils.subarray(image, offset, image.length);
+ }
+
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
/*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=151207
* Anton Leherbauer (Wind River Systems)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.util.CharArrayMap;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
/**
* Used to evaluate expressions in preprocessor directives.
// supported by GCC since 4.3 and by some other C compilers
// They consist of a prefix 0b or 0B, followed by a sequence of 0 and 1 digits
// see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html
- boolean isBin = false;
-
- boolean isHex = false;
- boolean isOctal = false;
-
- int pos= 0;
+
if (image.length > 1) {
if (image[0] == '0') {
- switch (image[++pos]) {
+ switch (image[1]) {
case 'b':
case 'B':
- isBin = true;
- ++pos;
- break;
+ return getNumber(image, 2, image.length, 2, IProblem.SCANNER_BAD_BINARY_FORMAT);
+
case 'x':
case 'X':
- isHex = true;
- ++pos;
- break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- isOctal = true;
- ++pos;
- break;
+ return getNumber(image, 2, image.length, 16, IProblem.SCANNER_BAD_HEX_FORMAT);
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return getNumber(image, 1, image.length, 8, IProblem.SCANNER_BAD_OCTAL_FORMAT);
}
}
}
- if (isBin) {
- return getNumber(image, 2, image.length, 2, IProblem.SCANNER_BAD_BINARY_FORMAT);
- }
- if (isHex) {
- return getNumber(image, 2, image.length, 16, IProblem.SCANNER_BAD_HEX_FORMAT);
- }
- if (isOctal) {
- return getNumber(image, 1, image.length, 8, IProblem.SCANNER_BAD_OCTAL_FORMAT);
- }
- return getNumber(image, 0, image.length, 10, IProblem.SCANNER_BAD_DECIMAL_FORMAT);
+
+ return getNumber(image, 0, image.length, 10, IProblem.SCANNER_BAD_DECIMAL_FORMAT);
}
public static long getChar(char[] tokenImage, int i) throws EvalException {
}
private static long getNumber(char[] tokenImage, int from, int to, int base, int problemID) throws EvalException {
- if (from == to) {
- throw new EvalException(problemID, tokenImage);
- }
- long result= 0;
- int i= from;
- for (; i < to; i++) {
- int digit= getDigit(tokenImage[i]);
- if (digit >= base) {
- break;
+ char c;
+ long result = 0;
+ int i = from;
+ if (from != to) {
+ for (; i < to; i++) {
+ int digit = getDigit(tokenImage[i]);
+ if (digit >= base) {
+ break;
+ }
+ result = result * base + digit;
+ }
+
+ if (i >= to) {
+ return result; // return early
+ }
+
+ c = tokenImage[i];
+ if ('0' <= c && c <= '9') {
+ // A suffix cannot start with a number
+ throw new EvalException(problemID, tokenImage);
+ } else if (i == 2 && base != 10) {
+ // Possible that the prefix is bad.
+ i--;
}
- result= result*base + digit;
+
+ } else {
+ /*
+ * If we get in here, then the number literal is 2 characters,
+ * but hasn't had the last character checked if it's a suffix
+ */
+ i = 1;
}
+ // The rest should be a suffix
+ final int suffixStart = i;
for (; i < to; i++) {
switch (tokenImage[i]) {
case 'u' : case 'l': case 'U': case 'L':
break;
default:
+ c = tokenImage[i];
+ if (Character.isLetterOrDigit(c) || c == '_') {
+ char[] suffix = CharArrayUtils.subarray(tokenImage, suffixStart, -1);
+ throw new EvalException(IProblem.SCANNER_CONSTANT_WITH_BAD_SUFFIX, suffix);
+ }
throw new EvalException(problemID, tokenImage);
}
}
/*******************************************************************************
- * Copyright (c) 2007, 2013 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* Markus Schorn - initial API and implementation
* Mike Kucera (IBM) - UTF string literals
* Sergey Prigogin (Google)
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
public boolean fSupportSlashPercentComments= false;
public boolean fSupportUTFLiterals= true;
public boolean fSupportRawStringLiterals= false;
+ public boolean fSupportUserDefinedLiterals = false;
public IncludeExportPatterns fIncludeExportPatterns;
@Override
if (fInsideIncludeDirective) {
return headerName(start, true);
}
- return stringLiteral(start, 1, IToken.tSTRING);
+ return stringLiteral(start, 1, IToken.tSTRING);
case '\'':
return charLiteral(start, IToken.tCHAR);
c= nextCharPhase3();
}
}
-
- private Token stringLiteral(final int start, int length, final int tokenType) throws OffsetLimitReachedException {
+
+ private boolean isIdentifierStart(int c) {
+ return Character.isLetter((char)c) ||
+ Character.isDigit((char)c) ||
+ Character.isUnicodeIdentifierPart(c) ||
+ (fOptions.fSupportDollarInIdentifiers && c == '$') ||
+ (fOptions.fSupportAtSignInIdentifiers && c == '@') ||
+ c == '_';
+ }
+
+ private Token stringLiteral(final int start, int length, int tokenType) throws OffsetLimitReachedException {
boolean escaped = false;
boolean done = false;
length++;
c= nextCharPhase3();
}
+
+ if (fOptions.fSupportUserDefinedLiterals && isUDLSuffixStart(c)) {
+ Token t = identifier(start + length, 0);
+ tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
+ length += t.getLength();
+ }
+
return newToken(tokenType, start, length);
}
- private Token rawStringLiteral(final int start, int length, final int tokenType) throws OffsetLimitReachedException {
+ private boolean isUDLSuffixStart(int c) {
+ // C++11 introduced a backward incompatible change breaking the following code:
+ // #define __STDC_FORMAT_MACROS
+ // #include <inttypes.h>
+ // #include <stdio.h>
+ //
+ // void test() {
+ // int64_t i64 = 123;
+ // printf("My int64: %"PRId64"\n", i64);
+ // }
+ //
+ // We follow the example of Clang and GCC that are working around this by interpreting literal
+ // suffixes that don't start with underscores as separate tokens, which allows them to expand
+ // as macros: http://llvm.org/viewvc/llvm-project?view=rev&revision=152287 and
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52538
+ return c == '_';
+ }
+
+ private Token rawStringLiteral(final int start, int length, int tokenType) throws OffsetLimitReachedException {
final int delimOffset= fOffset;
int delimEndOffset = delimOffset;
int offset;
fEndOffset= offset;
fCharPhase3= 0;
nextCharPhase3();
+
+ if (fOptions.fSupportUserDefinedLiterals && isUDLSuffixStart(fCharPhase3)) {
+ Token t = identifier(offset, 0);
+ tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
+ offset += t.getLength();
+ }
+
return newToken(tokenType, start, offset - start);
}
- private Token charLiteral(final int start, final int tokenType) throws OffsetLimitReachedException {
+ private Token charLiteral(final int start, int tokenType) throws OffsetLimitReachedException {
boolean escaped = false;
boolean done = false;
int length= tokenType == IToken.tCHAR ? 1 : 2;
length++;
c= nextCharPhase3();
}
+
+ if (fOptions.fSupportUserDefinedLiterals && isIdentifierStart(c)) {
+ Token t = identifier(start+length, 0);
+ tokenType = IToken.tUSER_DEFINED_CHAR_LITERAL;
+ length += t.getLength();
+ }
+
return newToken(tokenType, start, length);
}
/*******************************************************************************
- * Copyright (c) 2009 IBM Corporation and others.
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* Contributors:
* Mike Kucera (IBM) - Initial API and implementation
+ * Richard Eames
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
* @throws IllegalArgumentException if the tokenVal does not represent a string literal
*/
public static StringType fromToken(int tokenVal) {
- switch(tokenVal) {
+ switch (tokenVal) {
case IToken.tSTRING: return NARROW;
case IToken.tLSTRING: return WIDE;
case IToken.tUTF16STRING: return UTF16;
throw new IllegalArgumentException(tokenVal + " is not a string token");
}
}
+
+ /**
+ * Returns the StringType for a given string literal token, including a user-defined string literal
+ * @see StringType#fromToken(int)
+ * @since 5.10
+ */
+ public static StringType fromToken(IToken token) {
+ switch (token.getType()) {
+ case IToken.tSTRING: return NARROW;
+ case IToken.tLSTRING: return WIDE;
+ case IToken.tUTF16STRING: return UTF16;
+ case IToken.tUTF32STRING: return UTF32;
+ case IToken.tUSER_DEFINED_STRING_LITERAL: {
+ char[] image = token.getCharImage();
+ switch (image[0]) {
+ case 'R':
+ case '"': return NARROW;
+ case 'L': return WIDE;
+ case 'u':
+ if (image.length > 3 && image[1] == '8') {
+ return NARROW;
+ }
+ return UTF16;
+ case 'U': return UTF32;
+ }
+ }
+ //$FALL-THROUGH$
+ default:
+ throw new IllegalArgumentException(token.getType() + " is not a string token");
+ }
+ }
}
/*******************************************************************************
- * Copyright (c) 2008 IBM Corporation and others All rights reserved. This
+ * Copyright (c) 2008, 2015 IBM Corporation and others All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
return true;
}
+ @Override
+ public boolean supportUserDefinedLiterals() {
+ return false;
+ }
}
/*******************************************************************************
- * Copyright (c) 2013 QNX Software Systems and others.
+ * Copyright (c) 2013, 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@Deprecated
public void setScanComments(boolean val) {
}
+
+ @Override
+ public char[] getAdditionalNumericLiteralSuffixes() {
+ return new char[] {};
+ }
}