/******************************************************************************** * Copyright (c) 2025-2026 ZF Friedrichshafen AG * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #include "includes.h" #include "lexer_test.h" #include "../../../sdv_executables/sdv_idl_compiler/lexer.cpp" #include "../../../sdv_executables/sdv_idl_compiler/exception.cpp" #include "../../../sdv_executables/sdv_idl_compiler/codepos.cpp" #include "../../../sdv_executables/sdv_idl_compiler/token.cpp" #include "../../../sdv_executables/sdv_idl_compiler/tokenlist.cpp" #include "../../../sdv_executables/sdv_idl_compiler/constvariant.inl" void CLexerTest::SetUpTestCase() { ASSERT_TRUE(true); } void CLexerTest::TearDownTestCase() {} void CLexerTest::SetUp() {} void CLexerTest::TearDown() {} TEST_F(CLexerTest, Instantiate) { // Instantiate a code object without code (should throw exception): EXPECT_THROW(CCodePos(nullptr), CCompileException); EXPECT_NO_THROW(CCodePos("")); EXPECT_TRUE(CCodePos("").IsValid()); // Instantiate lexer without callback (should throw exception) EXPECT_THROW(CLexer(nullptr, true), CCompileException); SLexerDummyCallback sCallback; EXPECT_NO_THROW(CLexer lexer(&sCallback, true)); } TEST_F(CLexerTest, ParsingLocation) { const char szCode[] = R"code(identifier1 identifier2 identifier3 identifier4 R"(abc def)" identifier5 0x1234 )code"; // Check locations CCodePos code(szCode); SLexerDummyCallback sCallback; CLexer lexer(&sCallback, true); CToken sLocIdentifier1 = lexer.GetToken(code, nullptr); CToken sLocIdentifier2 = lexer.GetToken(code, nullptr); CToken sLocIdentifier3 = lexer.GetToken(code, nullptr); CToken sLocIdentifier4 = lexer.GetToken(code, nullptr); CToken sLocLiteral1 = lexer.GetToken(code, nullptr); CToken sLocIdentifier5 = lexer.GetToken(code, nullptr); CToken sLocLiteral2 = lexer.GetToken(code, nullptr); EXPECT_EQ(sLocIdentifier1.GetLine(), 1u); EXPECT_EQ(sLocIdentifier1.GetCol(), 1u); EXPECT_EQ(sLocIdentifier2.GetLine(), 2u); EXPECT_EQ(sLocIdentifier2.GetCol(), 1u); EXPECT_EQ(sLocIdentifier3.GetLine(), 3u); EXPECT_EQ(sLocIdentifier3.GetCol(), 3u); EXPECT_EQ(sLocIdentifier4.GetLine(), 4u); EXPECT_EQ(sLocIdentifier4.GetCol(), 5u); EXPECT_EQ(sLocLiteral1.GetLine(), 5u); EXPECT_EQ(sLocLiteral1.GetCol(), 5u); EXPECT_EQ(sLocIdentifier5.GetLine(), 7u); EXPECT_EQ(sLocIdentifier5.GetCol(), 5u); EXPECT_EQ(sLocLiteral2.GetLine(), 8u); EXPECT_EQ(sLocLiteral2.GetCol(), 7u); } TEST_F(CLexerTest, EmptyString) { // Parse empty string CCodePos codeEmptyString(""); EXPECT_TRUE(codeEmptyString.HasEOF()); SLexerDummyCallback sCallback; EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeEmptyString, nullptr), CToken()); EXPECT_TRUE(codeEmptyString.HasEOF()); } TEST_F(CLexerTest, Whitespace) { // Parse whitespace string SLexerStoreCallback sCallback; // Parse code with only whitespace. CCodePos codeWhitespaceString1(" \t\r\n "); EXPECT_FALSE(codeWhitespaceString1.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString1, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t\r\n "); EXPECT_TRUE(codeWhitespaceString1.HasEOF()); EXPECT_EQ(codeWhitespaceString1.GetLine(), 2u); EXPECT_EQ(codeWhitespaceString1.GetCol(), 2u); // Parse code with only whitespace and limit parsing to one line only. CCodePos codeWhitespaceString2(" \t\r\n "); EXPECT_FALSE(codeWhitespaceString2.HasEOF()); CLexer lexerWhitespaceString2(&sCallback, true, CLexer::ELexingMode::lexing_preproc); EXPECT_EQ(lexerWhitespaceString2.GetToken(codeWhitespaceString2, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t"); EXPECT_FALSE(codeWhitespaceString2.HasEOF()); EXPECT_EQ(codeWhitespaceString2.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString2.GetCol(), 5u); CCodePos codeWhitespaceString3(" \t\n "); EXPECT_FALSE(codeWhitespaceString3.HasEOF()); CLexer lexerWhitespaceString3(&sCallback, true, CLexer::ELexingMode::lexing_preproc); EXPECT_EQ(lexerWhitespaceString3.GetToken(codeWhitespaceString3, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t"); EXPECT_FALSE(codeWhitespaceString3.HasEOF()); EXPECT_EQ(codeWhitespaceString3.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString3.GetCol(), 5u); // Parse code with only whitespace with concatenating lines and limit parsing to one line only. CCodePos codeWhitespaceString5(" \t\\\r\n "); EXPECT_FALSE(codeWhitespaceString5.HasEOF()); CLexer lexerWhitespaceString5(&sCallback, true, CLexer::ELexingMode::lexing_preproc); EXPECT_EQ(lexerWhitespaceString5.GetToken(codeWhitespaceString5, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t\\\r\n "); EXPECT_TRUE(codeWhitespaceString5.HasEOF()); EXPECT_EQ(codeWhitespaceString5.GetLine(), 2u); EXPECT_EQ(codeWhitespaceString5.GetCol(), 2u); CCodePos codeWhitespaceString4(" \t\\\n "); EXPECT_FALSE(codeWhitespaceString4.HasEOF()); CLexer lexerWhitespaceString4(&sCallback, true, CLexer::ELexingMode::lexing_preproc); EXPECT_EQ(lexerWhitespaceString4.GetToken(codeWhitespaceString4, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t\\\n "); EXPECT_TRUE(codeWhitespaceString4.HasEOF()); EXPECT_EQ(codeWhitespaceString4.GetLine(), 2u); EXPECT_EQ(codeWhitespaceString4.GetCol(), 2u); // TODO.... //EXPECT_EQ(sCallback.ssComment, "//Multi line comment"); //CCodePos codeCommentStr10("/*Multi line comment\r\nmore comment*/"); //CToken token = lexerCommentStr9.GetToken(codeCommentStr10, nullptr); //EXPECT_EQ(token.GetLine(), 1u); //EXPECT_EQ(token.GetEndLine(), 2u); //EXPECT_EQ(token.GetCol(), 1); //EXPECT_EQ(token.GetEndCol(), 14); } TEST_F(CLexerTest, WhitespaceTabAlignment) { // Parse whitespace string SLexerStoreCallback sCallback; // Parse code with only whitespace. CCodePos codeWhitespaceString1("\t"); EXPECT_FALSE(codeWhitespaceString1.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString1, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), "\t"); EXPECT_TRUE(codeWhitespaceString1.HasEOF()); EXPECT_EQ(codeWhitespaceString1.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString1.GetCol(), 5u); CCodePos codeWhitespaceString2(" \t"); EXPECT_FALSE(codeWhitespaceString2.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString2, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t"); EXPECT_TRUE(codeWhitespaceString2.HasEOF()); EXPECT_EQ(codeWhitespaceString2.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString2.GetCol(), 5u); CCodePos codeWhitespaceString3(" \t"); EXPECT_FALSE(codeWhitespaceString3.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString3, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t"); EXPECT_TRUE(codeWhitespaceString3.HasEOF()); EXPECT_EQ(codeWhitespaceString3.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString3.GetCol(), 5u); CCodePos codeWhitespaceString4(" \t"); EXPECT_FALSE(codeWhitespaceString4.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString4, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), " \t"); EXPECT_TRUE(codeWhitespaceString4.HasEOF()); EXPECT_EQ(codeWhitespaceString4.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString4.GetCol(), 9u); CCodePos codeWhitespaceString5("\t\t"); EXPECT_FALSE(codeWhitespaceString5.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString5, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), "\t\t"); EXPECT_TRUE(codeWhitespaceString5.HasEOF()); EXPECT_EQ(codeWhitespaceString5.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString5.GetCol(), 9u); CCodePos codeWhitespaceString6("\t\t "); EXPECT_FALSE(codeWhitespaceString6.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString6, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), "\t\t "); EXPECT_TRUE(codeWhitespaceString6.HasEOF()); EXPECT_EQ(codeWhitespaceString6.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString6.GetCol(), 10u); CCodePos codeWhitespaceString7("\t \t "); EXPECT_FALSE(codeWhitespaceString7.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString7, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), "\t \t "); EXPECT_TRUE(codeWhitespaceString7.HasEOF()); EXPECT_EQ(codeWhitespaceString7.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString7.GetCol(), 10u); CCodePos codeWhitespaceString8("\t \t "); EXPECT_FALSE(codeWhitespaceString8.HasEOF()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeWhitespaceString8, nullptr), CToken()); EXPECT_EQ(static_cast(sCallback.tokenWhitespace), "\t \t "); EXPECT_TRUE(codeWhitespaceString8.HasEOF()); EXPECT_EQ(codeWhitespaceString8.GetLine(), 1u); EXPECT_EQ(codeWhitespaceString8.GetCol(), 14u); } TEST_F(CLexerTest, PreprocessorLines) { // Parse preprocessor command SLexerStoreCallback sCallback; CCodePos code1("#define abc"); CLexer(&sCallback, true).GetToken(code1, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc"); CCodePos code2(" #define abc"); CLexer(&sCallback, true).GetToken(code2, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc"); CCodePos code3("/* abc preproc */ #define abc"); CLexer(&sCallback, true).GetToken(code3, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc"); CCodePos code4("#define abc // Preproc"); CLexer(&sCallback, true).GetToken(code4, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc // Preproc"); CCodePos code5("#define abc \\\r\ndef\r\nghi"); CLexer(&sCallback, true).GetToken(code5, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc \\\r\ndef\r\n"); CCodePos code6("#define abc \\\ndef\nghi"); CLexer(&sCallback, true).GetToken(code6, nullptr); EXPECT_EQ(sCallback.ssPreprocLine, "#define abc \\\ndef\n"); CCodePos codeNotPreprocessorStr("identifier #define abc"); CLexer lexer(&sCallback, true); lexer.GetToken(codeNotPreprocessorStr, nullptr); EXPECT_THROW(lexer.GetToken(codeNotPreprocessorStr, nullptr), CCompileException); } TEST_F(CLexerTest, Identifier) { // Get itdentifier SLexerDummyCallback sCallback; CCodePos code1("identifier"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "identifier"); CCodePos code2("identifier"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_identifier); CCodePos code3("__identifier"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr), "__identifier"); CCodePos code4("attribute"); EXPECT_NE(CLexer(&sCallback, true).GetToken(code4, nullptr).GetType(), ETokenType::token_identifier); CCodePos code5("AttriBUTE"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "AttriBUTE"); code5.Reset(); EXPECT_THROW(CLexer(&sCallback, false).GetToken(code5, nullptr), CCompileException); CCodePos code6("_attribute"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "_attribute"); CCodePos code7("iden_tifier"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "iden_tifier"); CCodePos code8("__identifier__"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "__identifier__"); CCodePos code9(" identifier"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "identifier"); CCodePos code10(" {identifier"); EXPECT_NE(CLexer(&sCallback, true).GetToken(code10, nullptr).GetType(), ETokenType::token_identifier); } TEST_F(CLexerTest, InvalidIdentifier) { SLexerDummyCallback sCallback; CCodePos code1(" 1identifier"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code1, nullptr), CCompileException); CCodePos code2(" identifier\""); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code2, nullptr), CCompileException); CCodePos code3(" identifier\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code3, nullptr), CCompileException); } TEST_F(CLexerTest, Keyword) { SLexerDummyCallback sCallback; // Compare each keyword for (const std::string& rssKeyword : g_vecOmgIdlKeywords) { // Check for keyword. CCodePos codeKeyword(rssKeyword.c_str()); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeKeyword, nullptr), rssKeyword.c_str()); codeKeyword.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(codeKeyword, nullptr).GetType(), ETokenType::token_keyword); // Keyword prepended with '_' is an identifier. std::string ssIdentifier = std::string("_") + rssKeyword; CCodePos codeIdentifier(ssIdentifier.c_str()); EXPECT_NE(CLexer(&sCallback, true).GetToken(codeIdentifier, nullptr).GetType(), ETokenType::token_keyword); // Keyword with different case writing is illegal if not case sensitive (is not an identifier). std::string ssCaseDiffKeyword = rssKeyword; bool bLower = false; for (char& rc : ssCaseDiffKeyword) { rc = bLower ? static_cast(std::tolower(rc)) : static_cast(std::toupper(rc)); bLower = !bLower; } CCodePos codeCaseDiffKeyword(ssCaseDiffKeyword.c_str()); EXPECT_NO_THROW(CLexer(&sCallback, true).GetToken(codeCaseDiffKeyword, nullptr)); codeCaseDiffKeyword.Reset(); EXPECT_THROW(CLexer(&sCallback, false).GetToken(codeCaseDiffKeyword, nullptr), CCompileException); } } TEST_F(CLexerTest, Separator) { // Has separator SLexerDummyCallback sCallback; CCodePos code1("{"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "{"); CCodePos code2("{"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_separator); CCodePos code3("("); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr), "("); CCodePos code4("["); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "["); CCodePos code5("]"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "]"); CCodePos code6(")"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), ")"); CCodePos code7("}"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "}"); CCodePos code8(":"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), ":"); CCodePos code9(";"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), ";"); CCodePos code10("."); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "."); CCodePos code11(" {"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "{"); CCodePos code12(" text{"); EXPECT_NE(CLexer(&sCallback, true).GetToken(code12, nullptr).GetType(), ETokenType::token_separator); } TEST_F(CLexerTest, Operator) { // Has operator SLexerDummyCallback sCallback; CCodePos code1("+"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "+"); CCodePos code2("+"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_operator); CCodePos code3("-"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr), "-"); CCodePos code4("*"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "*"); CCodePos code5("/"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "/"); CCodePos code6("%"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "%"); CCodePos code7("^"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "^"); CCodePos code8("~"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "~"); CCodePos code9(","); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), ","); CCodePos code10("|"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "|"); CCodePos code11("||"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "||"); CCodePos code12("&"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "&"); CCodePos code13("&&"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code13, nullptr), "&&"); CCodePos code14("="); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code14, nullptr), "="); CCodePos code15("=="); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code15, nullptr), "=="); CCodePos code16("!"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code16, nullptr), "!"); CCodePos code17("!="); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code17, nullptr), "!="); CCodePos code18("<"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code18, nullptr), "<"); CCodePos code19("<="); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code19, nullptr), "<="); CCodePos code20(">"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code20, nullptr), ">"); CCodePos code21(">="); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code21, nullptr), ">="); CCodePos code22(" +"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code22, nullptr), "+"); CCodePos code23(" text+"); EXPECT_NE(CLexer(&sCallback, true).GetToken(code23, nullptr).GetType(), ETokenType::token_operator); // This will be detected as preprocessor directive CCodePos code24("#"); EXPECT_NE(CLexer(&sCallback, true).GetToken(code24, nullptr), "#"); // This will be detected as operator directive code24.Reset(); EXPECT_EQ(CLexer(&sCallback, true, CLexer::ELexingMode::lexing_preproc).GetToken(code24, nullptr), "#"); } TEST_F(CLexerTest, DecimalIntegerLiteral) { // Has literal SLexerDummyCallback sCallback; CCodePos code1("1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "1234"); CCodePos code2("1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_dec_integer); CCodePos code4("1234u"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "1234u"); CCodePos code5("1234U"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "1234U"); CCodePos code6("1234l"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "1234l"); CCodePos code7("1234L"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "1234L"); CCodePos code8("1234ul"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "1234ul"); CCodePos code9("1234UL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "1234UL"); CCodePos code10("1234ll"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "1234ll"); CCodePos code11("1234LL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "1234LL"); CCodePos code12("1234ull"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "1234ull"); CCodePos code13("1234ULL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code13, nullptr), "1234ULL"); } TEST_F(CLexerTest, OctalIntegerLiteral) { SLexerDummyCallback sCallback; CCodePos code1("01234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "01234"); CCodePos code2("01234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("01234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_oct_integer); CCodePos code4("01234l"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "01234l"); CCodePos code5("01234L"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "01234L"); CCodePos code6("01234ll"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "01234ll"); CCodePos code7("01234LL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "01234LL"); CCodePos code8("01234u"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "01234u"); CCodePos code9("01234U"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "01234U"); CCodePos code10("01234ul"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "01234ul"); CCodePos code11("01234UL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "01234UL"); CCodePos code12("01234ull"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "01234ull"); CCodePos code13("01234ULL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code13, nullptr), "01234ULL"); } TEST_F(CLexerTest, HexIntegerLiteral) { SLexerDummyCallback sCallback; CCodePos code1("0xaBcDu"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "0xaBcDu"); CCodePos code2("0xaBcDu"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("0xaBcDu"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_hex_integer); CCodePos code4("0xaBcDU"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "0xaBcDU"); CCodePos code5("0xaBcDl"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "0xaBcDl"); CCodePos code6("0xaBcDL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "0xaBcDL"); CCodePos code7("0xaBcDul"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "0xaBcDul"); CCodePos code8("0xaBcDUL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "0xaBcDUL"); CCodePos code9("0xaBcDll"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "0xaBcDll"); CCodePos code10("0xaBcDLL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "0xaBcDLL"); CCodePos code11("0xaBcDull"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "0xaBcDull"); CCodePos code12("0xaBcDULL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "0xaBcDULL"); } TEST_F(CLexerTest, BinaryIntegerLiteral) { SLexerDummyCallback sCallback; CCodePos code1("0b1010"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "0b1010"); CCodePos code2("0b1010"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("0b1010"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_bin_integer); CCodePos code4("0b0010l"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "0b0010l"); CCodePos code5("0b1010L"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "0b1010L"); CCodePos code6("0b0010ll"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "0b0010ll"); CCodePos code7("0b1010LL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "0b1010LL"); CCodePos code8("0b1010u"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "0b1010u"); CCodePos code9("0b1010U"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "0b1010U"); CCodePos code10("0b1010ul"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "0b1010ul"); CCodePos code11("0b1010UL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "0b1010UL"); CCodePos code12("0b1010ull"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "0b1010ull"); CCodePos code13("0b1010ULL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code13, nullptr), "0b1010ULL"); } TEST_F(CLexerTest, DecimalFloatingPointLiteral) { SLexerDummyCallback sCallback; CCodePos code1("1234."); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "1234."); CCodePos code2("1234."); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("1234."); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_dec_floating_point); CCodePos code4("1234.5"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "1234.5"); CCodePos code5(".5"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), ".5"); CCodePos code6("1234e5"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "1234e5"); CCodePos code7("1234e-5f"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "1234e-5f"); CCodePos code8("1234e+5F"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "1234e+5F"); CCodePos code9("1234e-5L"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "1234e-5L"); CCodePos code10("1234e+5l"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "1234e+5l"); } TEST_F(CLexerTest, HexadecimalFloatingPointLiteral) { SLexerDummyCallback sCallback; CCodePos code1("0x1ffp10"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "0x1ffp10"); CCodePos code2("0x1ffp10"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("0x1ffp10"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_hex_floating_point); CCodePos code4("0x0p-1"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "0x0p-1"); CCodePos code5("0x1.p0"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "0x1.p0"); CCodePos code6("0xf.p-1"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "0xf.p-1"); CCodePos code7("0x0.123p-1"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "0x0.123p-1"); CCodePos code8("0xa.bp10l"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "0xa.bp10l"); } TEST_F(CLexerTest, FixedPointLiteral) { SLexerDummyCallback sCallback; CCodePos code1("1234.d"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "1234.d"); CCodePos code2("1234.d"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("1234.d"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_fixed_point); CCodePos code4("1234.5D"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "1234.5D"); CCodePos code5(".5D"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), ".5D"); } TEST_F(CLexerTest, ASCIIStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("\"...\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "\"...\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_string); } TEST_F(CLexerTest, ASCIIRawStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("R\"abc(...\")abc..\")abc\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "R\"abc(...\")abc..\")abc\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_raw_string); } TEST_F(CLexerTest, UTF8StringLiteral) { SLexerDummyCallback sCallback; CCodePos code("u8\"...\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "u8\"...\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_string); } TEST_F(CLexerTest, UTF8RawStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("u8R\"abc(...\")abc..\")abc\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "u8R\"abc(...\")abc..\")abc\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_raw_string); } TEST_F(CLexerTest, UTF16StringLiteral) { SLexerDummyCallback sCallback; CCodePos code("u\"...\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "u\"...\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_string); } TEST_F(CLexerTest, UTF16RawStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("uR\"abc(...\")abc..\")abc\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "uR\"abc(...\")abc..\")abc\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_raw_string); } TEST_F(CLexerTest, UTF32StringLiteral) { SLexerDummyCallback sCallback; CCodePos code("U\"...\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "U\"...\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_string); } TEST_F(CLexerTest, UTF32RawStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("UR\"abc(...\")abc..\")abc\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "UR\"abc(...\")abc..\")abc\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_raw_string); } TEST_F(CLexerTest, WideStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("L\"...\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "L\"...\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_string); } TEST_F(CLexerTest, WideRawStringLiteral) { SLexerDummyCallback sCallback; CCodePos code("LR\"abc(...\")abc..\")abc\""); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "LR\"abc(...\")abc..\")abc\""); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_raw_string); } TEST_F(CLexerTest, ASCIICharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code("\'x\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "\'x\'"); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character); } TEST_F(CLexerTest, UTF16CharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code("u\'x\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "u\'x\'"); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character); } TEST_F(CLexerTest, UTF32CharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code("U\'x\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "U\'x\'"); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character); } TEST_F(CLexerTest, WideCharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code("L\'x\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr), "L\'x\'"); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetType(), ETokenType::token_literal); code.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character); } TEST_F(CLexerTest, InvalidCharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code("u8\'x\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code, nullptr), CCompileException); } TEST_F(CLexerTest, ASCIICharacterSequenceLiteral) { SLexerDummyCallback sCallback; CCodePos code1("\'ab\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "\'ab\'"); CCodePos code2("\'ab\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("\'ab\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character_sequence); CCodePos code4("\'abcd\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "\'abcd\'"); CCodePos code5("\'abc\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code5, nullptr), CCompileException); CCodePos code6("\'abcdefgh\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "\'abcdefgh\'"); } TEST_F(CLexerTest, WideCharacterSequenceLiteral) { SLexerDummyCallback sCallback; CCodePos code1("L\'ab\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "L\'ab\'"); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetType(), ETokenType::token_literal); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character_sequence); // Dependable on the size of wchar_t two or four byte wide character sequences are possible CCodePos code2("L\'abcd\'"); if constexpr (sizeof(wchar_t) == 4) // size if four bytes EXPECT_THROW(CLexer(&sCallback, true).GetToken(code2, nullptr), CCompileException); else // size if two bytes EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr), "L\'abcd\'"); CCodePos code3("L\'abc\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code3, nullptr), CCompileException); CCodePos code4("L\'abcdefgh\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code4, nullptr), CCompileException); } TEST_F(CLexerTest, InvalidCharacterSequences) { SLexerDummyCallback sCallback; CCodePos code1("u\'ab\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code1, nullptr), CCompileException); CCodePos code2("u8\'ab\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code2, nullptr), CCompileException); CCodePos code3("U\'ab\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code3, nullptr), CCompileException); } TEST_F(CLexerTest, EscapeCharacterLiteral) { SLexerDummyCallback sCallback; CCodePos code1("\'\\\'\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "\'\\\'\'"); CCodePos code2("\'\\'\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr).GetType(), ETokenType::token_literal); CCodePos code3("\'\\'\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_character); CCodePos code4("\'\\\"\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "\'\\\"\'"); CCodePos code5("\'\\?\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "\'\\?\'"); CCodePos code6("\'\\\\\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code6, nullptr), "\'\\\\\'"); CCodePos code7("\'\\b\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code7, nullptr), "\'\\b\'"); CCodePos code8("\'\\f\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code8, nullptr), "\'\\f\'"); CCodePos code9("\'\\n\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code9, nullptr), "\'\\n\'"); CCodePos code10("\'\\r\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code10, nullptr), "\'\\r\'"); CCodePos code11("\'\\t\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code11, nullptr), "\'\\t\'"); CCodePos code12("\'\\v\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code12, nullptr), "\'\\v\'"); CCodePos code13("\'\\265\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code13, nullptr), "\'\\265\'"); // µ character CCodePos code14("\'\\xb5\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code14, nullptr), "\'\\xb5\'"); // µ character CCodePos code15("\'\\xB5\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code15, nullptr), "\'\\xB5\'"); // µ character CCodePos code16("\'\\u00B5\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code16, nullptr), "\'\\u00B5\'"); // µ character CCodePos code17("\'\\U000000b5\'"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code17, nullptr), "\'\\U000000b5\'"); // µ character CCodePos code18("\'\\u0B5\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code18, nullptr), CCompileException); CCodePos code19("\'\\U00b5\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code19, nullptr), CCompileException); CCodePos code20("\'\\q\'"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code20, nullptr), CCompileException); } TEST_F(CLexerTest, BooleanLiteral) { SLexerDummyCallback sCallback; CCodePos code1("true"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "true"); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetType(), ETokenType::token_literal); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_boolean); CCodePos code2("TRUE"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr), "TRUE"); CCodePos code3("false"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr), "false"); CCodePos code4("FALSE"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "FALSE"); } TEST_F(CLexerTest, NullptrLiteral) { SLexerDummyCallback sCallback; CCodePos code1("nullptr"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "nullptr"); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetType(), ETokenType::token_literal); code1.Reset(); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr).GetLiteralType(), ETokenLiteralType::token_literal_nullptr); CCodePos code2("NULL"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr), "NULL"); } TEST_F(CLexerTest, LiteralFollowingWhitespace) { SLexerDummyCallback sCallback; CCodePos code1(" 1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code1, nullptr), "1234"); CCodePos code2(" +1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code2, nullptr), "+"); CCodePos code3(" -1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code3, nullptr), "-"); CCodePos code4(" {-}1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code4, nullptr), "{"); CCodePos code5(" abc1234"); EXPECT_EQ(CLexer(&sCallback, true).GetToken(code5, nullptr), "abc1234"); CCodePos code6(" 1234a"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code6, nullptr), CCompileException); CCodePos code7(" 012348"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code7, nullptr), CCompileException); CCodePos code8(" 0xabcdg1234"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code8, nullptr), CCompileException); CCodePos code9(" 0b111112"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code9, nullptr), CCompileException); CCodePos code10(" \"..."); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code10, nullptr), CCompileException); CCodePos code11(" u8\"..."); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code11, nullptr), CCompileException); CCodePos code12(" u\"..."); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code12, nullptr), CCompileException); CCodePos code13(" U\"..."); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code13, nullptr), CCompileException); CCodePos code14(" L\"..."); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code14, nullptr), CCompileException); CCodePos code15(" uR\"abc(...)abcd\""); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code15, nullptr), CCompileException); CCodePos code16(" uR\"abc(...)ab\""); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code16, nullptr), CCompileException); CCodePos code17(" uR\"abc(...)abc"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(code17, nullptr), CCompileException); } TEST_F(CLexerTest, Comments) { // Parse comment string SLexerStoreCallback sCallback; CCodePos codeCommentStr1(" /*comment*/"); CLexer(&sCallback, true).GetToken(codeCommentStr1, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "/*comment*/"); CCodePos codeCommentStr2(" //comment\r\n"); CLexer(&sCallback, true).GetToken(codeCommentStr2, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "//comment\r\n"); CCodePos codeCommentStr3(" /*comment*//*next comment*/"); CLexer(&sCallback, true).GetToken(codeCommentStr3, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "/*next comment*/"); CCodePos codeCommentStr4(" //comment\r\n//next comment"); CLexer(&sCallback, true).GetToken(codeCommentStr4, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "//next comment"); CCodePos codeCommentStr5(" //comment\n//next comment"); CLexer(&sCallback, true).GetToken(codeCommentStr5, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "//next comment"); CCodePos codeCommentStr6(" /*comment\r\nmore comment*/"); CLexer(&sCallback, true).GetToken(codeCommentStr6, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "/*comment\r\nmore comment*/"); CCodePos codeCommentStr7("/*unfinished comment"); EXPECT_THROW(CLexer(&sCallback, true).GetToken(codeCommentStr7, nullptr), CCompileException); CCodePos codeCommentStr8("/*Multi line comment\nmore comment*/"); CLexer lexerCommentStr8(&sCallback, true, CLexer::ELexingMode::lexing_preproc); EXPECT_THROW(lexerCommentStr8.GetToken(codeCommentStr8, nullptr), CCompileException); CCodePos codeCommentStr9("//Multi line comment\r\n//more comment"); CLexer lexerCommentStr9(&sCallback, true); lexerCommentStr9.GetToken(codeCommentStr9, nullptr); EXPECT_EQ(static_cast(sCallback.tokenComment), "//more comment"); CLexer lexerCommentStr10(&sCallback, true); CCodePos codeCommentStr10("//Single line comment\r\n struct"); lexerCommentStr10.GetToken(codeCommentStr10, nullptr); EXPECT_EQ(sCallback.tokenComment.GetLine(), 1u); EXPECT_EQ(sCallback.tokenComment.GetEndLine(), 1u); EXPECT_EQ(sCallback.tokenComment.GetCol(), 1u); EXPECT_EQ(sCallback.tokenComment.GetEndCol(), 23u); CLexer lexerCommentStr11(&sCallback, true); CCodePos codeCommentStr11("/*Multi line comment\r\nmore comment*/"); lexerCommentStr11.GetToken(codeCommentStr11, nullptr); EXPECT_EQ(sCallback.tokenComment.GetLine(), 1u); EXPECT_EQ(sCallback.tokenComment.GetEndLine(), 2u); EXPECT_EQ(sCallback.tokenComment.GetCol(), 1u); EXPECT_EQ(sCallback.tokenComment.GetEndCol(), 14u); } TEST_F(CLexerTest, ComplexParsing) { const char szCode[] = R"code(identifier1 identifier2 /*comment*/ identifier3 identifier4 // comment /*comment*/ /*more comment*/R"(abc def)" identifier5 0x1234 )code"; // Check locations CCodePos codeStr(szCode); SLexerDummyCallback sCallback; CLexer lexer(&sCallback, true); EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "identifier1"); EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "identifier2"); EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "identifier3"); EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "identifier4"); CToken sLiteralLoc = lexer.GetToken(codeStr, nullptr); EXPECT_TRUE(sLiteralLoc == "R\"(abc\r\ndef)\"" || // Windows sLiteralLoc == "R\"(abc\ndef)\""); // Linux EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "identifier5"); EXPECT_EQ(lexer.GetToken(codeStr, nullptr), "0x1234"); } TEST_F(CLexerTest, ParsingCustom) { // Parse string SLexerDummyCallback sCallback; CLexer lexer(&sCallback, true); CCodePos code1("This is a text\""); EXPECT_EQ(lexer.GetCustom(code1, '\"'), "This is a text"); CCodePos code2("This is a text\"abc"); EXPECT_EQ(lexer.GetCustom(code2, '\"'), "This is a text"); CCodePos code3("This is a text"); EXPECT_EQ(lexer.GetCustom(code3, '\"'), "This is a text"); CCodePos code4("\"This is a text\"abc"); EXPECT_EQ(lexer.GetCustom(code4, '\"'), ""); CCodePos code5("#include // ABC"); EXPECT_EQ(lexer.GetCustom(code5, '>'), "#include