Bug 379684 Support for User Defined Literals
authorRichard Eames <eclipse@naddiseo.ca>
Fri, 23 Jan 2015 02:10:37 +0000 (19:10 -0700)
committerSergey Prigogin <eclipse.sprigogin@gmail.com>
Tue, 7 Jul 2015 04:38:55 +0000 (00:38 -0400)
This patch adds preliminary support for C++11 user defined literals:
* Syntax support
* Type deduction in expressions
* Template literal operators
* String literal concatenation

Change-Id: I8a9760036a2c8428295f0e1ffb4b519a0a2577c9
Signed-off-by: Richard Eames <eclipse@naddiseo.ca>
27 files changed:
core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PortedScannerTests.java
core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTests.java
core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTestsBase.java
core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/AbstractScannerExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/GNUScannerExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/IScannerExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/AbstractCPPParserExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/GPPScannerExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/parser/cpp/ICPPParserExtensionConfiguration.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IProblem.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScanner.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTProblem.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclSpecifier.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java
core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/StringType.java
lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/ScannerExtensionConfiguration.java
qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/parser/StringScanner.java

index 5fbb690..5ab7b41 100644 (file)
@@ -14,6 +14,7 @@
  *     Thomas Corbat (IFS)
  *     Nathan Ridge
  *     Marc-Andre Laperle
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.parser.tests.ast2;
 
@@ -53,12 +54,14 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
 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;
@@ -134,6 +137,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
 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;
@@ -256,6 +260,21 @@ public class AST2CPPTests extends AST2TestBase {
                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);
@@ -11142,4 +11161,375 @@ public class AST2CPPTests extends AST2TestBase {
        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
+       }
 }
index c7dbe6b..8b335ea 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -1796,9 +1796,9 @@ public class PortedScannerTests extends PreprocessorTestsBase {
                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());
index 022d3f3..99775d8 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -8,6 +8,7 @@
  * Contributors:
  *     IBM - Initial API and implementation
  *     Markus Schorn (Wind River Systems)
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.parser.tests.scanner;
 
@@ -16,6 +17,7 @@ import java.util.List;
 
 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;
 
@@ -219,9 +221,23 @@ public class PreprocessorTests extends PreprocessorTestsBase {
 
        // #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);
 
@@ -1329,13 +1345,40 @@ public class PreprocessorTests extends PreprocessorTestsBase {
                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");
        }
 }
index 8b2a7c6..ad652ae 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -12,8 +12,6 @@ package org.eclipse.cdt.core.parser.tests.scanner;
 
 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;
@@ -36,6 +34,8 @@ import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
 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;
@@ -150,6 +150,10 @@ public abstract class PreprocessorTestsBase extends BaseTestCase {
                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 + "'");
        }
index d0c3f61..f9e1031 100644 (file)
@@ -21,12 +21,14 @@ import java.util.Set;
 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;
@@ -45,6 +47,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
 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;
 
@@ -175,7 +178,11 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti
                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; }
        //
@@ -1978,4 +1985,296 @@ public abstract class IndexCPPBindingResolutionTest extends IndexBindingResoluti
                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);
+       }
 }
index 7cd1717..b798fc5 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -8,6 +8,7 @@
  * Contributors:
  *     Anton Leherbauer (Wind River Systems) - initial API and implementation
  *     Markus Schorn (Wind River Systems)
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.dom.parser;
 
@@ -111,6 +112,15 @@ public abstract class AbstractScannerExtensionConfiguration implements IScannerE
                return false;
        }
        
+       /**
+        * {@inheritDoc}
+        * @since 5.11
+        */
+       @Override
+       public boolean supportUserDefinedLiterals() {
+               return false;
+       }
+       
        @Override
        public CharArrayIntMap getAdditionalPreprocessorKeywords() {
                return fAddPreprocessorKeywords;
index 5a507d8..bed8877 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -10,6 +10,7 @@
  *     Anton Leherbauer (Wind River Systems)
  *     Markus Schorn (Wind River Systems)
  *     Sergey Prigogin (Google)
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.dom.parser;
 
@@ -89,7 +90,15 @@ public abstract class GNUScannerExtensionConfiguration extends AbstractScannerEx
        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.
index 839dbbb..e729c8f 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -115,4 +115,10 @@ public interface IScannerExtensionConfiguration {
         * @since 5.5
         */
        public boolean supportRawStringLiterals();
+               
+       /**
+        * Support for User Defined Literals such as 123_suffix
+        * @since 5.11
+        */
+       public boolean supportUserDefinedLiterals();
 }
index 36cef5e..dab46c4 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -8,6 +8,7 @@
  * 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;
 
@@ -116,7 +117,19 @@ public abstract class AbstractCPPParserExtensionConfiguration implements ICPPPar
        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());
index addb207..e4c9baf 100644 (file)
@@ -11,6 +11,7 @@
  *     Anton Leherbauer (Wind River Systems)
  *     Markus Schorn (Wind River Systems)
  *     Sergey Prigogin (Google)
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.dom.parser.cpp;
 
@@ -133,4 +134,13 @@ public class GPPScannerExtensionConfiguration extends GNUScannerExtensionConfigu
     public boolean supportRawStringLiterals() {
        return true;
     }
+
+       /**
+        * User Defined Literals
+        * @since 5.10
+        */
+       @Override
+       public boolean supportUserDefinedLiterals() {
+               return true;
+       }
 }
index da48b13..48fa17d 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -137,6 +137,13 @@ public interface ICPPParserExtensionConfiguration {
         * @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.
index 0f037e9..311b49b 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  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
@@ -7,6 +7,7 @@
  * 
  *  Contributors:
  *      John Camelon (IBM Corporation) - initial API and implementation
+ *      Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.core.parser;
 
@@ -221,7 +222,19 @@ public interface IProblem {
         * @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.  
@@ -305,12 +318,12 @@ public interface IProblem {
         * 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;
        
        /**
@@ -327,6 +340,12 @@ public interface IProblem {
        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;
index 03c1074..2d203b7 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -118,4 +118,11 @@ public interface IScanner {
         */
        @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();
 }
index b13d697..4094b17 100644 (file)
@@ -188,11 +188,13 @@ public interface IToken {
        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;
index 6b04283..be9ca34 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -57,7 +57,7 @@ public class ASTProblem extends ASTNode implements IASTProblem {
        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), 
@@ -88,6 +88,12 @@ public class ASTProblem extends ASTNode implements IASTProblem {
                        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), 
index 2a7f431..7240bfc 100644 (file)
@@ -9,6 +9,7 @@
  *     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;
 
@@ -16,16 +17,22 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
 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;
@@ -45,6 +52,8 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
     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() {
@@ -54,6 +63,11 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
                this.fKind = kind;
                this.fValue = value;
        }
+       
+       public CPPASTLiteralExpression(int kind, char[] value, char[] suffix) {
+               this(kind, value);
+               this.setSuffix(suffix);
+       }
 
        @Override
        public CPPASTLiteralExpression copy() {
@@ -62,8 +76,10 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
        
        @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);
        }
 
@@ -89,7 +105,76 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
        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);
     }
@@ -186,9 +271,41 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
                }
                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':
@@ -198,21 +315,25 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
        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);
@@ -221,36 +342,236 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
        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';
        }
 
     /**
@@ -292,15 +613,13 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
                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;
        }
index 1809865..6a440cc 100644 (file)
@@ -108,7 +108,7 @@ public class CPPASTSimpleDeclSpecifier extends CPPASTBaseDeclSpecifier
                case eVoid:
                        return t_void;
                case eNullPtr:
-                       // Null pointer type cannot be expressed wit ha simple decl specifier.
+                       // Null pointer type cannot be expressed wita simple decl specifier.
                        break;
        }
        return t_unspecified;
index d6ce647..cd943e5 100644 (file)
@@ -44,6 +44,7 @@ public class CPPBasicType implements ICPPBasicType, ISerializableType {
        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;
 
index b2b6762..83e06a7 100644 (file)
@@ -16,6 +16,7 @@
  *     Thomas Corbat (IFS)
  *     Anders Dahlberg (Ericsson) - bug 84144
  *     Nathan Ridge
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.internal.core.dom.parser.cpp;
 
@@ -195,12 +196,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
     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;
@@ -229,10 +232,12 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
         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(
@@ -843,6 +848,29 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
                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) {
@@ -1790,29 +1818,45 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
        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());
@@ -1869,6 +1913,22 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
             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 {
@@ -1877,6 +1937,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
         case IToken.tLSTRING:
         case IToken.tUTF16STRING:
         case IToken.tUTF32STRING:
+        case IToken.tUSER_DEFINED_STRING_LITERAL:
                break;
         default:
                throwBacktrack(LA(1));
index 7676d86..2d24255 100644 (file)
  *     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;
@@ -83,6 +85,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId;
 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;
@@ -151,6 +154,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
 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;
@@ -195,6 +199,7 @@ import org.eclipse.cdt.internal.core.dom.parser.IRecursionResolvingBinding;
 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;
@@ -206,8 +211,10 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
 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;
@@ -3050,6 +3057,156 @@ public class CPPSemantics {
 
        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);
index a099ea3..8f8b9c5 100644 (file)
@@ -1,5 +1,5 @@
 ###############################################################################
-# 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
@@ -9,6 +9,7 @@
 #     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}
@@ -25,6 +26,7 @@ ScannerProblemFactory.error.preproc.invalidDirective=Invalid preprocessor direct
 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 
@@ -41,6 +43,8 @@ ScannerProblemFactory.error.scanner.illegalIdentifier=Illegal identifier in defi
 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 ';'
index 6466810..6b9617f 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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;
@@ -294,6 +296,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
         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);
@@ -386,7 +389,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
        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) {
@@ -620,14 +632,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
                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);
@@ -638,7 +649,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
        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}.
@@ -715,11 +726,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
      */
     @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) {
@@ -741,24 +753,34 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
        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);
@@ -773,23 +795,30 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
                    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;
                
@@ -841,7 +870,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
        }
        
        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);
                }
@@ -850,6 +884,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
 
        Token internalFetchToken(final ScannerContext uptoEndOfCtx, int options, boolean withinExpansion)
                        throws OffsetLimitReachedException {
+               
+               
         Token ppToken= fCurrentContext.currentLexerToken();
         while (true) {
                        switch (ppToken.getType()) {
@@ -966,6 +1002,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
         boolean isHex = false;
         boolean isOctal = false;
         boolean hasDot= false;
+        
+        boolean badSuffix = false;
 
         int pos= 0;
         if (image.length > 1) {
@@ -1002,6 +1040,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
                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
@@ -1069,38 +1111,71 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
                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,
@@ -1953,6 +2028,25 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
         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) {
index 3600410..ec04602 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -10,6 +10,7 @@
  *     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;
 
@@ -19,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
 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.
@@ -352,42 +354,26 @@ public class ExpressionEvaluator {
         // 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 {
@@ -425,23 +411,50 @@ public class ExpressionEvaluator {
        }
 
        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);
                        }
                }
index 810a954..894350a 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -9,6 +9,7 @@
  *     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;
 
@@ -57,6 +58,7 @@ final public class Lexer implements ITokenSequence {
                public boolean fSupportSlashPercentComments= false;
                public boolean fSupportUTFLiterals= true;
                public boolean fSupportRawStringLiterals= false;
+               public boolean fSupportUserDefinedLiterals = false; 
                public IncludeExportPatterns fIncludeExportPatterns;
                
                @Override
@@ -348,7 +350,7 @@ final public class Lexer implements ITokenSequence {
                                if (fInsideIncludeDirective) {
                                        return headerName(start, true);
                                }
-                               return stringLiteral(start, 1, IToken.tSTRING);
+                               return stringLiteral(start, 1, IToken.tSTRING);
 
                        case '\'':
                                return charLiteral(start, IToken.tCHAR);
@@ -732,8 +734,17 @@ final public class Lexer implements ITokenSequence {
                        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;
                
@@ -766,10 +777,35 @@ final public class Lexer implements ITokenSequence {
                        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;
@@ -813,10 +849,17 @@ final public class Lexer implements ITokenSequence {
                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;
@@ -848,6 +891,13 @@ final public class Lexer implements ITokenSequence {
                        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);
        }
        
index ac0152b..1ebeae4 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     Mike Kucera (IBM) - Initial API and implementation
+ *     Richard Eames
  *******************************************************************************/
 package org.eclipse.cdt.internal.core.parser.scanner;
 
@@ -59,7 +60,7 @@ public enum StringType {
         * @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;
@@ -68,4 +69,35 @@ public enum StringType {
                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");
+               }
+       }
 }
index 502ec24..881c875 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -41,4 +41,8 @@ public class ScannerExtensionConfiguration extends AbstractScannerExtensionConfi
                return true;
        }
 
+       @Override
+       public boolean supportUserDefinedLiterals() {
+               return false;
+       }
 }
index b1372de..58404b1 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -116,4 +116,9 @@ public class StringScanner implements IScanner {
        @Deprecated
        public void setScanComments(boolean val) {
        }
+
+       @Override
+       public char[] getAdditionalNumericLiteralSuffixes() {
+               return new char[] {};
+       }
 }