mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 06:32:10 +02:00
Bug 379684 Support for User Defined Literals
This patch adds preliminary support for C++11 user defined litrals: * Syntax support * Type deduction in expressions * Template literal operators * String literal concatenation I made quite a few changes in CPPASTLiteralExpression so that it more closely follows the spec when parsing numbers. And I'd like some feedback on the changes I made to CPPSemantics with regards to template literal operators. There are also some questions I have marked in comments, which I would appreciate an answer to. Change-Id: I242ecb8f5706f516a4c891fea268a668e5e4a694 Signed-off-by: Richard Eames <eclipse@naddiseo.ca> Reviewed-on: https://git.eclipse.org/r/24367 Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com> Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
This commit is contained in:
parent
88d0024075
commit
f5942dac81
26 changed files with 1434 additions and 177 deletions
|
@ -14,6 +14,7 @@
|
|||
* Thomas Corbat (IFS)
|
||||
* Nathan Ridge
|
||||
* Marc-Andre Laperle
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.parser.tests.ast2;
|
||||
|
||||
|
@ -54,12 +55,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;
|
||||
|
@ -133,6 +136,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;
|
||||
|
@ -251,6 +255,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");
|
||||
}
|
||||
|
||||
// #define CURLOPTTYPE_OBJECTPOINT 10000
|
||||
// #define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number
|
||||
// typedef enum {
|
||||
|
@ -10577,4 +10596,378 @@ public class AST2CPPTests extends AST2TestBase {
|
|||
public void testU8TokenAfterIfdef_429361() 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 = 123X;
|
||||
public void testUserDefinedLiteralOperatorTypes1() throws Exception {
|
||||
checkUserDefinedLiteralIsRet(getAboveComment());
|
||||
}
|
||||
|
||||
// class Ret {};
|
||||
// Ret operator "" X(long double i) { return Ret(); }
|
||||
// auto test = 12.3X;
|
||||
public void testUserDefinedLiteralOperatorTypes2() throws Exception {
|
||||
checkUserDefinedLiteralIsRet(getAboveComment());
|
||||
}
|
||||
|
||||
// class Ret {};
|
||||
// Ret operator "" X(const char* s) { return Ret(); }
|
||||
// auto test = 123X;
|
||||
public void testUserDefinedLiteralOperatorTypes1a() throws Exception {
|
||||
checkUserDefinedLiteralIsRet(getAboveComment());
|
||||
}
|
||||
|
||||
// class Ret {};
|
||||
// Ret operator "" X(const char* s) { return Ret(); }
|
||||
// auto test = 12.3X;
|
||||
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 = 123X;
|
||||
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.3X;
|
||||
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 = 123X;
|
||||
public void testUserDefinedLiteralOperatorTypes4a() throws Exception {
|
||||
checkUserDefinedLiteralIsRet(getAboveComment());
|
||||
}
|
||||
|
||||
// class Ret {};
|
||||
// template<char... Chars> Ret operator "" X() { return Ret(); }
|
||||
// auto test = 123.123X;
|
||||
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 testUserDefinedLiteralBadConcat1() 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 = 123X;
|
||||
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.123X;
|
||||
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 = 123X;
|
||||
/*public void testUserDefinedLiteralResolution3() throws Exception {
|
||||
// TODO(Richard Eames): Enable this test when I figure out how to
|
||||
// display a problem.
|
||||
BindingAssertionHelper bh = new BindingAssertionHelper(getAboveComment(), true);
|
||||
// resolution is abiguous
|
||||
bh.assertProblem("test", 4);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -1809,9 +1809,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() );
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -18,6 +19,7 @@ import junit.framework.TestSuite;
|
|||
|
||||
import org.eclipse.cdt.core.parser.IProblem;
|
||||
import org.eclipse.cdt.core.parser.IToken;
|
||||
import org.eclipse.cdt.core.parser.ParserLanguage;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -222,8 +224,22 @@ public class PreprocessorTests extends PreprocessorTestsBase {
|
|||
// #define tp(x,y) #x##y
|
||||
// tp(a, );
|
||||
// tp(a,b);
|
||||
public void testStringifyAndPaste() throws Exception {
|
||||
initializeScanner();
|
||||
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 testStringifyAndPasteC() throws Exception {
|
||||
initializeScanner(getAboveComment(), ParserLanguage.C);
|
||||
validateString("a");
|
||||
validateToken(IToken.tSEMI);
|
||||
|
||||
|
@ -1355,13 +1371,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, ParserLanguage.C);
|
||||
fullyTokenize();
|
||||
validateProblemCount(5);
|
||||
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 fift are invalid in c++11
|
||||
String badbinary = "{0b012, 0b01b, 0b1111e01, 0b1111p10, 0b10010.10010}";
|
||||
initializeScanner(badbinary);
|
||||
fullyTokenize();
|
||||
validateProblemCount(5);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
validateProblem(i, IProblem.SCANNER_BAD_BINARY_FORMAT, null);
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,6 +152,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 + "'");
|
||||
}
|
||||
|
|
|
@ -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.7
|
||||
*/
|
||||
@Override
|
||||
public boolean supportUserDefinedLiterals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharArrayIntMap getAdditionalPreprocessorKeywords() {
|
||||
return fAddPreprocessorKeywords;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -90,6 +91,14 @@ public abstract class GNUScannerExtensionConfiguration extends AbstractScannerEx
|
|||
return "ij".toCharArray(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.7
|
||||
*/
|
||||
@Override
|
||||
public boolean supportUserDefinedLiterals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated simply derive from this class and use {@link #addMacro(String, String)} to
|
||||
* add additional macros.
|
||||
|
|
|
@ -115,4 +115,10 @@ public interface IScannerExtensionConfiguration {
|
|||
* @since 5.5
|
||||
*/
|
||||
public boolean supportRawStringLiterals();
|
||||
|
||||
/**
|
||||
* Support for User Defined Literals such as 123_suffix
|
||||
* @since 5.7
|
||||
*/
|
||||
public boolean supportUserDefinedLiterals();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -154,6 +155,15 @@ public abstract class AbstractCPPParserExtensionConfiguration implements ICPPPar
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 5.7
|
||||
*/
|
||||
@Override
|
||||
public boolean supportUserDefinedLiterals() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration#getBuiltinBindingsProvider()
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -123,4 +124,13 @@ public class GPPScannerExtensionConfiguration extends GNUScannerExtensionConfigu
|
|||
public boolean supportRawStringLiterals() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* User Defined Literals
|
||||
* @since 5.7
|
||||
*/
|
||||
@Override
|
||||
public boolean supportUserDefinedLiterals() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,13 @@ public interface ICPPParserExtensionConfiguration {
|
|||
*/
|
||||
public boolean supportFunctionStyleAssembler();
|
||||
|
||||
/**
|
||||
* Support user-defined literal expressions:
|
||||
* (char_expr | string_expr | int_expr | float_expr) ud-suffix
|
||||
* @since 5.7
|
||||
*/
|
||||
public boolean supportUserDefinedLiterals();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getBuiltinBindingsProvider()} instead.
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*
|
||||
* Contributors:
|
||||
* John Camelon (IBM Corporation) - initial API and implementation
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.parser;
|
||||
|
||||
|
@ -222,6 +223,18 @@ public interface IProblem {
|
|||
*/
|
||||
public final static int SCANNER_BAD_BINARY_FORMAT = SCANNER_RELATED | 0x00F;
|
||||
|
||||
/**
|
||||
* Invalid suffix on constant
|
||||
* @since 5.7
|
||||
*/
|
||||
public final static int SCANNER_CONSTANT_WITH_BAD_SUFFIX = SCANNER_RELATED | 0x010;
|
||||
|
||||
/**
|
||||
* Invalid prefix on float
|
||||
* @since 5.7
|
||||
*/
|
||||
public final static int SCANNER_FLOAT_WITH_BAD_PREFIX = SCANNER_RELATED | 0x011;
|
||||
|
||||
// Preprocessor
|
||||
/**
|
||||
* #error encountered by Preprocessor.
|
||||
|
@ -326,6 +339,12 @@ public interface IProblem {
|
|||
*/
|
||||
public final static int PREPROCESSOR_EXCEEDS_MAXIMUM_INCLUSION_DEPTH= PREPROCESSOR_RELATED | 0x00F;
|
||||
|
||||
/**
|
||||
* During concatentation of string literals, at least two were found with
|
||||
* more than one type of UDL suffix
|
||||
* @since 5.7
|
||||
*/
|
||||
public final static int PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION = PREPROCESSOR_RELATED | 0x010;
|
||||
/**
|
||||
* Syntax error, detected by the parser.
|
||||
*/
|
||||
|
|
|
@ -189,11 +189,13 @@ public interface IToken {
|
|||
int tLSTRING = 131;
|
||||
/** @since 5.1 */ int tUTF16STRING = 5000;
|
||||
/** @since 5.1 */ int tUTF32STRING = 5001;
|
||||
/** @since 5.7 */ int tUSER_DEFINED_STRING_LITERAL = 5700;
|
||||
|
||||
int tCHAR = 132;
|
||||
int tLCHAR = 133;
|
||||
/** @since 5.1 */ int tUTF16CHAR = 5002;
|
||||
/** @since 5.1 */ int tUTF32CHAR = 5003;
|
||||
/** @since 5.7 */ int tUSER_DEFINED_CHAR_LITERAL = 5701;
|
||||
|
||||
int t__Bool = 134;
|
||||
int t__Complex = 135;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* Andrew Ferguson (Symbian)
|
||||
* Markus Schorn (Wind River Systems)
|
||||
* Sergey Prigogin (Google)
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.parser.util;
|
||||
|
||||
|
@ -298,15 +299,38 @@ public class CharArrayUtils {
|
|||
}
|
||||
|
||||
public static final int lastIndexOf(char[] toBeFound, char[] array) {
|
||||
return lastIndexOf(toBeFound, array, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.7
|
||||
*/
|
||||
public static int lastIndexOf(char toBeFound, char[] array) {
|
||||
return lastIndexOf(toBeFound, array, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.7
|
||||
*/
|
||||
public static int lastIndexOf(char toBeFound, char[] array, int fromIndex) {
|
||||
return lastIndexOf(new char[]{toBeFound}, array, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.7
|
||||
*/
|
||||
public static int lastIndexOf(char[] toBeFound, char[] array, int fromIndex) {
|
||||
int j = toBeFound.length - 1;
|
||||
for (int i = array.length; --i >= 0;) {
|
||||
for (int i = array.length; --i >= fromIndex;) {
|
||||
if (toBeFound[j] == array[i]) {
|
||||
if (--j == -1)
|
||||
if (--j == -1) {
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
j = toBeFound.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Contributors:
|
||||
* John Camelon (IBM) - Initial API and implementation
|
||||
* Markus Schorn (Wind River Systems)
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||
|
||||
|
@ -15,15 +16,21 @@ 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.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;
|
||||
|
@ -42,6 +49,8 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
|
||||
private int kind;
|
||||
private char[] value = CharArrayUtils.EMPTY;
|
||||
private char[] suffix = CharArrayUtils.EMPTY;
|
||||
private boolean isCompilerSuffix = true;
|
||||
private ICPPEvaluation fEvaluation;
|
||||
|
||||
public CPPASTLiteralExpression() {
|
||||
|
@ -52,6 +61,11 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
public CPPASTLiteralExpression(int kind, char[] value, char[] suffix) {
|
||||
this(kind, value);
|
||||
this.setSuffix(suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPPASTLiteralExpression copy() {
|
||||
return copy(CopyStyle.withoutLocations);
|
||||
|
@ -59,8 +73,10 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
|
||||
@Override
|
||||
public CPPASTLiteralExpression copy(CopyStyle style) {
|
||||
CPPASTLiteralExpression copy =
|
||||
new CPPASTLiteralExpression(kind, value == null ? null : value.clone());
|
||||
CPPASTLiteralExpression copy = new CPPASTLiteralExpression(kind,
|
||||
value == null ? null : value.clone(),
|
||||
suffix == null ? null : suffix.clone());
|
||||
copy.setOffsetAndLength(this);
|
||||
return copy(copy, style);
|
||||
}
|
||||
|
||||
|
@ -86,6 +102,75 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
this.value= value;
|
||||
}
|
||||
|
||||
public char[] getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(char[] suffix) {
|
||||
this.suffix = 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 (kind) {
|
||||
case lk_float_constant:
|
||||
case lk_integer_constant:
|
||||
int udOffset = (value[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(value, udOffset, -1));
|
||||
for (int i = 0; i < suffix.length; i++) {
|
||||
switch (suffix[i]) {
|
||||
case 'l': case 'L':
|
||||
case 'u': case 'U':
|
||||
case 'f': case 'F':
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < compilerSuffixes.length; j++) {
|
||||
if (suffix[i] == compilerSuffixes[j]) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
isCompilerSuffix = false;
|
||||
// Remove the suffix from the value if it's a UDL
|
||||
setValue(CharArrayUtils.subarray(value, 0, udOffset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case lk_string_literal:
|
||||
{
|
||||
final int offset = CharArrayUtils.lastIndexOf('"', value, CharArrayUtils.indexOf('"', value) + 1);
|
||||
if (offset > 0) {
|
||||
setSuffix(CharArrayUtils.subarray(value, offset + 1, -1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case lk_char_constant:
|
||||
{
|
||||
final int offset = CharArrayUtils.lastIndexOf('\'', value, CharArrayUtils.indexOf('\'', value) + 1);
|
||||
if (offset > 0) {
|
||||
setSuffix(CharArrayUtils.subarray(value, offset + 1, -1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(value);
|
||||
|
@ -137,8 +222,40 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
return Value.create(length);
|
||||
}
|
||||
|
||||
private Kind getCharType() {
|
||||
switch (getValue()[0]) {
|
||||
private IType getStringType() {
|
||||
if (suffix.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 suffix.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(), suffix); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public Kind getBasicCharKind() {
|
||||
switch (value[0]) {
|
||||
case 'L':
|
||||
return Kind.eWChar;
|
||||
case 'u':
|
||||
|
@ -151,11 +268,12 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
}
|
||||
|
||||
private IType classifyTypeOfFloatLiteral() {
|
||||
final char[] lit= getValue();
|
||||
final char[] lit= suffix;
|
||||
final int len= lit.length;
|
||||
Kind kind= Kind.eDouble;
|
||||
int flags= 0;
|
||||
if (len > 0) {
|
||||
if (isCompilerSuffix) {
|
||||
switch (lit[len - 1]) {
|
||||
case 'f': case 'F':
|
||||
kind= Kind.eFloat;
|
||||
|
@ -164,6 +282,9 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
flags |= IBasicType.IS_LONG;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return getUserDefinedLiteralOperatorType();
|
||||
}
|
||||
}
|
||||
return new CPPBasicType(kind, flags, this);
|
||||
}
|
||||
|
@ -171,8 +292,10 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
private IType classifyTypeOfIntLiteral() {
|
||||
int makelong= 0;
|
||||
boolean unsigned= false;
|
||||
final char[] lit= suffix;
|
||||
int flags= 0;
|
||||
|
||||
final char[] lit= getValue();
|
||||
if (isCompilerSuffix) {
|
||||
for (int i= lit.length - 1; i >= 0; i--) {
|
||||
final char c= lit[i];
|
||||
if (!(c > 'f' && c <= 'z') && !(c > 'F' && c <= 'Z')) {
|
||||
|
@ -190,7 +313,6 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
}
|
||||
}
|
||||
|
||||
int flags= 0;
|
||||
if (unsigned) {
|
||||
flags |= IBasicType.IS_UNSIGNED;
|
||||
}
|
||||
|
@ -200,9 +322,210 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
|
|||
} 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 = value[i++];
|
||||
|
||||
if (c == '0' && i < value.length) {
|
||||
// Probably octal/hex/binary
|
||||
c = value[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 < value.length) {
|
||||
c = value[++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 = value[i];
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[++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 = value[i];
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[++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;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with the expectation that value[i] == '.'
|
||||
*/
|
||||
private int afterDecimalPoint(int i) {
|
||||
char c = value[++i];
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[++i];
|
||||
}
|
||||
|
||||
if ((c | 0x20) == 'e') {
|
||||
return exponentPart(i);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with the expectation that c == 'e'
|
||||
*/
|
||||
private int exponentPart(int i) {
|
||||
char c = value[++i];
|
||||
|
||||
// optional '+' or '-'
|
||||
if (c == '+' || c == '-') {
|
||||
c = value[++i];
|
||||
}
|
||||
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[++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 = value[++i];
|
||||
|
||||
if (c == '1' || c == '0') {
|
||||
while (c == '1' || c == '0' && i < value.length) {
|
||||
c = value[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 = value[++i];
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[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 = value[++i];
|
||||
if (isHexDigit(c)) {
|
||||
while (isHexDigit(c) && i < value.length) {
|
||||
c = value[++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 value[i] == '.'
|
||||
private int hexFloatAfterDecimal(int i) {
|
||||
// 0xHHH.
|
||||
char c = value[++i];
|
||||
if (isHexDigit(c)) {
|
||||
while (isHexDigit(c) && i < value.length) {
|
||||
c = value[++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 = value[++i];
|
||||
|
||||
if (c == '-' || c == '+') {
|
||||
c = value[++i];
|
||||
}
|
||||
|
||||
if (Character.isDigit(c)) {
|
||||
while (Character.isDigit(c) && i < value.length) {
|
||||
c = value[++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';
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated, use {@link #setValue(char[])}, instead.
|
||||
*/
|
||||
|
@ -242,15 +565,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());
|
||||
return new EvalFixed(getCharType(), PRVALUE, createCharValue());
|
||||
case lk_float_constant:
|
||||
return new EvalFixed(classifyTypeOfFloatLiteral(), PRVALUE, Value.UNKNOWN);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* Andrew Ferguson (Symbian)
|
||||
* Sergey Prigogin (Google)
|
||||
* Thomas Corbat (IFS)
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||
|
||||
|
@ -159,6 +160,7 @@ import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.BranchPoint;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.Variant;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
|
||||
|
||||
/**
|
||||
* This is our implementation of the IParser interface, serving as a parser for
|
||||
|
@ -176,12 +178,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;
|
||||
|
@ -208,9 +212,11 @@ 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);
|
||||
additionalNumericalSuffixes = ((CPreprocessor) scanner).getAdditionalNumericLiteralSuffixes();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -787,6 +793,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) {
|
||||
|
@ -1731,28 +1760,45 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
IToken t = null;
|
||||
IASTLiteralExpression literalExpression = null;
|
||||
IASTLiteralExpression leWithRange = null;
|
||||
|
||||
switch (LT(1)) {
|
||||
// TO DO: we need more literals...
|
||||
case IToken.tINTEGER:
|
||||
t = consume();
|
||||
literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage());
|
||||
return setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
leWithRange = setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
((CPPASTLiteralExpression) literalExpression).calculateSuffix(additionalNumericalSuffixes);
|
||||
break;
|
||||
case IToken.tFLOATINGPT:
|
||||
t = consume();
|
||||
literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage());
|
||||
return setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
leWithRange = setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
((CPPASTLiteralExpression) literalExpression).calculateSuffix(additionalNumericalSuffixes);
|
||||
break;
|
||||
case IToken.tSTRING:
|
||||
case IToken.tLSTRING:
|
||||
case IToken.tUTF16STRING:
|
||||
case IToken.tUTF32STRING:
|
||||
return stringLiteral();
|
||||
case IToken.tUSER_DEFINED_STRING_LITERAL:
|
||||
leWithRange = stringLiteral();
|
||||
if (supportUserDefinedLiterals) {
|
||||
((CPPASTLiteralExpression) leWithRange).calculateSuffix();
|
||||
}
|
||||
break;
|
||||
case IToken.tCHAR:
|
||||
case IToken.tLCHAR:
|
||||
case IToken.tUTF16CHAR:
|
||||
case IToken.tUTF32CHAR:
|
||||
case IToken.tUSER_DEFINED_CHAR_LITERAL:
|
||||
t = consume();
|
||||
literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_char_constant, t.getImage());
|
||||
return setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
literalExpression = nodeFactory.newLiteralExpression(
|
||||
IASTLiteralExpression.lk_char_constant, t.getImage());
|
||||
leWithRange = setRange(literalExpression, t.getOffset(), t.getEndOffset());
|
||||
if (supportUserDefinedLiterals) {
|
||||
((CPPASTLiteralExpression) leWithRange).calculateSuffix();
|
||||
}
|
||||
break;
|
||||
case IToken.t_false:
|
||||
t = consume();
|
||||
literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_false, t.getImage());
|
||||
|
@ -1806,6 +1852,20 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (supportUserDefinedLiterals) {
|
||||
IToken la = LA(1);
|
||||
ASTNode loc = (ASTNode) leWithRange.getOriginalNode();
|
||||
if (la.getType() == IToken.tIDENTIFIER && loc != null) {
|
||||
if (loc.getOffset()+loc.getLength() != la.getOffset()) {
|
||||
return leWithRange;
|
||||
}
|
||||
IToken opName = consume(IToken.tIDENTIFIER);
|
||||
((CPPASTLiteralExpression) leWithRange).setSuffix(opName.getCharImage());
|
||||
setRange(leWithRange, loc.getOffset(), opName.getEndOffset());
|
||||
}
|
||||
}
|
||||
|
||||
return leWithRange;
|
||||
}
|
||||
|
||||
private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, BacktrackException {
|
||||
|
@ -1814,6 +1874,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));
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* Mike Kucera (IBM)
|
||||
* Thomas Corbat (IFS)
|
||||
* Nathan Ridge
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||
|
||||
|
@ -83,6 +84,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;
|
||||
|
@ -194,17 +196,23 @@ 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.CPPASTTemplateId;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPCompositeBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionInstance;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate;
|
||||
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.CPPTemplateParameterMap;
|
||||
|
@ -229,6 +237,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Contex
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
|
||||
import org.eclipse.cdt.internal.core.index.IIndexScope;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
|
@ -3021,6 +3030,159 @@ 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.
|
||||
*
|
||||
* XXX: why does findBindings return PDOMNodes?
|
||||
*/
|
||||
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 PDOMNode) {
|
||||
continue;
|
||||
}
|
||||
if (binding instanceof CPPFunction || binding instanceof ICPPFunctionTemplate) {
|
||||
funcs[i++] = (ICPPFunction) binding;
|
||||
if (binding instanceof ICPPFunctionTemplate) {
|
||||
tplFunctions[j++] = (ICPPFunctionTemplate) binding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
funcs = ArrayUtil.trim(funcs);
|
||||
tplFunctions = ArrayUtil.trim(tplFunctions);
|
||||
|
||||
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
|
||||
CPPPointerType charArray = new CPPPointerType(new CPPBasicType(Kind.eChar, 0, null), true, false, false);
|
||||
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
|
||||
data.setFunctionArguments(false, createArgForType(exp, charArray));
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
|
||||
// TODO(Richard Eames): This is a mess, but I don't know a better way to do it
|
||||
|
||||
IBinding[] tplBindings = new IBinding[j];
|
||||
for (ICPPFunctionTemplate func : tplFunctions) {
|
||||
// Get an instance of each template given the char literals as
|
||||
// template arguments, then resolve.
|
||||
CPPASTTemplateId tplName = new CPPASTTemplateId(((CPPFunctionTemplate)func).getTemplateName().copy());
|
||||
for (char c : exp.getValue()) {
|
||||
tplName.addTemplateArgument(new CPPASTLiteralExpression(ICPPASTLiteralExpression.lk_char_constant, new char[]{ '\'', c, '\'' }));
|
||||
}
|
||||
data = new LookupData(tplName);
|
||||
tplBindings[--j] = resolveFunction(data, tplFunctions, true);
|
||||
}
|
||||
|
||||
// Do we have valid template and non-template bindings?
|
||||
if (ret != null && tplBindings.length == 1) {
|
||||
if (!(ret instanceof IProblemBinding) && tplBindings[0] instanceof CPPFunctionInstance) {
|
||||
// Ambiguity? It has two valid options, and the spec says it shouldn't
|
||||
// TODO(Richard Eames): How do I notify the editor of an error at this point?
|
||||
return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
|
||||
}
|
||||
|
||||
if ((ret instanceof IProblemBinding) && tplBindings[0] instanceof CPPFunctionInstance) {
|
||||
// Only the template binding is valid
|
||||
ret = tplBindings[0];
|
||||
}
|
||||
}
|
||||
} 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 operater "" X(str, len)
|
||||
*/
|
||||
CPPPointerType strType = new CPPPointerType(new CPPBasicType(((CPPASTLiteralExpression)exp).getBasicCharKind(), 0, null), true, false, false);
|
||||
CPPBasicType szType = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED, null);
|
||||
IASTInitializerClause[] initializer = new IASTInitializerClause[] {
|
||||
createArgForType(exp, strType),
|
||||
createArgForType(null, szType)
|
||||
};
|
||||
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);
|
||||
if (!(targetType instanceof ICPPFunctionType))
|
||||
|
|
|
@ -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 ';'
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
* Markus Schorn (Wind River Systems)
|
||||
* Sergey Prigogin (Google)
|
||||
* Marc-Andre Laperle (Ericsson)
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.parser.scanner;
|
||||
|
||||
|
@ -294,6 +295,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);
|
||||
|
@ -387,6 +389,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
return fLocationMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IScannerExtensionConfiguration#supportAdditionalNumericLiteralSuffixes
|
||||
* @since 5.7
|
||||
*/
|
||||
public char[] getAdditionalNumericLiteralSuffixes() {
|
||||
return fAdditionalNumericLiteralSuffixes;
|
||||
}
|
||||
|
||||
private void configureKeywords(ParserLanguage language, IScannerExtensionConfiguration configuration) {
|
||||
Keywords.addKeywordsPreprocessor(fPPKeywords);
|
||||
if (language == ParserLanguage.C) {
|
||||
|
@ -720,6 +730,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
}
|
||||
|
||||
Token t1= fetchToken();
|
||||
String udl_suffix = null;
|
||||
|
||||
final int tt1= t1.getType();
|
||||
switch (tt1) {
|
||||
|
@ -741,24 +752,33 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
case IToken.t_PRAGMA:
|
||||
handlePragmaOperator(t1);
|
||||
return nextToken();
|
||||
|
||||
case IToken.tUSER_DEFINED_STRING_LITERAL:
|
||||
udl_suffix = StringType.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.tUSER_DEFINED_STRING_LITERAL:
|
||||
if (udl_suffix == null) {
|
||||
udl_suffix = StringType.getUserDefinedLiteralSuffix(t2);
|
||||
} else if (!udl_suffix.equals(StringType.getUserDefinedLiteralSuffix(t2))) {
|
||||
handleProblem(IProblem.PREPROCESSOR_MULTIPLE_USER_DEFINED_SUFFIXES_IN_CONCATENATION, udl_suffix.toCharArray(), 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);
|
||||
|
@ -780,16 +800,23 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
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 + (udl_suffix == null ? 0 : udl_suffix.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 (udl_suffix != null) {
|
||||
udl_suffix.getChars(0, udl_suffix.length(), image, ++off);
|
||||
tokenType = IToken.tUSER_DEFINED_STRING_LITERAL;
|
||||
}
|
||||
t1= new TokenWithImage(tokenType, null, t1.getOffset(), endOffset, image);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -841,7 +868,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);
|
||||
}
|
||||
|
@ -967,6 +999,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
boolean isOctal = false;
|
||||
boolean hasDot= false;
|
||||
|
||||
boolean badSuffix = false;
|
||||
|
||||
int pos= 0;
|
||||
if (image.length > 1) {
|
||||
if (image[0] == '0') {
|
||||
|
@ -1002,6 +1036,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,10 +1107,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
break loop;
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
final char c= image[pos];
|
||||
c= image[pos];
|
||||
switch (c) {
|
||||
case 'u': case 'U': case 'L': case 'l':
|
||||
continue;
|
||||
|
@ -1080,12 +1121,42 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
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
|
||||
|
@ -1100,7 +1171,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private <T> T findInclusion(final String includeDirective, final boolean quoteInclude,
|
||||
|
|
|
@ -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.
|
||||
|
@ -351,41 +353,25 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getNumber(image, 0, image.length, 10, IProblem.SCANNER_BAD_DECIMAL_FORMAT);
|
||||
}
|
||||
|
||||
|
@ -424,11 +410,10 @@ 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);
|
||||
}
|
||||
char c;
|
||||
long result = 0;
|
||||
int i = from;
|
||||
if (from != to) {
|
||||
for (; i < to; i++) {
|
||||
int digit = getDigit(tokenImage[i]);
|
||||
if (digit >= base) {
|
||||
|
@ -436,11 +421,39 @@ public class ExpressionEvaluator {
|
|||
}
|
||||
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--;
|
||||
}
|
||||
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -733,7 +735,16 @@ final public class Lexer implements ITokenSequence {
|
|||
}
|
||||
}
|
||||
|
||||
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,17 @@ final public class Lexer implements ITokenSequence {
|
|||
length++;
|
||||
c= nextCharPhase3();
|
||||
}
|
||||
|
||||
if (fOptions.fSupportUserDefinedLiterals && isIdentifierStart(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 Token rawStringLiteral(final int start, int length, int tokenType) throws OffsetLimitReachedException {
|
||||
final int delimOffset= fOffset;
|
||||
int delimEndOffset = delimOffset;
|
||||
int offset;
|
||||
|
@ -813,10 +831,17 @@ final public class Lexer implements ITokenSequence {
|
|||
fEndOffset= offset;
|
||||
fCharPhase3= 0;
|
||||
nextCharPhase3();
|
||||
|
||||
if (fOptions.fSupportUserDefinedLiterals && isIdentifierStart(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 +873,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*
|
||||
* Contributors:
|
||||
* Mike Kucera (IBM) - Initial API and implementation
|
||||
* Richard Eames
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.parser.scanner;
|
||||
|
||||
|
@ -71,4 +72,50 @@ 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.7
|
||||
*/
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user-defined suffix of a user-define string literal
|
||||
* @param token
|
||||
* @return the suffix of the token, if it exists
|
||||
* @since 5.7
|
||||
*/
|
||||
public static String getUserDefinedLiteralSuffix(IToken token) {
|
||||
if (token.getType() == IToken.tUSER_DEFINED_STRING_LITERAL) {
|
||||
int offset = token.getImage().lastIndexOf('"');
|
||||
return token.getImage().substring(offset + 1);
|
||||
}
|
||||
return new String();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,4 +41,8 @@ public class ScannerExtensionConfiguration extends AbstractScannerExtensionConfi
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportUserDefinedLiterals() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue