Commit daa0f6f9 authored by Brad King's avatar Brad King

Add Lua-style long brackets and long comments to CMake language

Teach the CMake language parser to recognize Lua-style "long bracket"
arguments.  These start with two '[' separated by zero or more '='
characters e.g. "[[" or "[=[" or "[==[".  They end with two ']'
separated by the same number of '=' as the opening bracket.  There is no
nesting of brackets of the same level (number of '=').  No escapes,
variable expansion, or other processing is performed on the content
between such brackets so they always represent exactly one argument.

Also teach CMake to parse and ignore "long comment" syntax.  A long
comment starts with "#" immediately followed by an opening long bracket.
It ends at the matching close long bracket.

Teach the RunCMake.Syntax test to cover long bracket and long comment
cases.
parent a8c65234
......@@ -29,14 +29,14 @@ struct cmListFileParser
~cmListFileParser();
bool ParseFile();
bool ParseFunction(const char* name, long line);
void AddArgument(cmListFileLexer_Token* token,
bool AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim);
cmListFile* ListFile;
cmMakefile* Makefile;
const char* FileName;
cmListFileLexer* Lexer;
cmListFileFunction Function;
enum { SeparationOkay, SeparationWarning } Separation;
enum { SeparationOkay, SeparationWarning, SeparationError} Separation;
};
//----------------------------------------------------------------------------
......@@ -90,6 +90,10 @@ bool cmListFileParser::ParseFile()
{
haveNewline = true;
}
else if(token->type == cmListFileLexer_Token_CommentBracket)
{
haveNewline = false;
}
else if(token->type == cmListFileLexer_Token_Identifier)
{
if(haveNewline)
......@@ -301,7 +305,10 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
{
parenDepth++;
this->Separation = SeparationOkay;
this->AddArgument(token, cmListFileArgument::Unquoted);
if(!this->AddArgument(token, cmListFileArgument::Unquoted))
{
return false;
}
}
else if(token->type == cmListFileLexer_Token_ParenRight)
{
......@@ -311,20 +318,41 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
}
parenDepth--;
this->Separation = SeparationOkay;
this->AddArgument(token, cmListFileArgument::Unquoted);
if(!this->AddArgument(token, cmListFileArgument::Unquoted))
{
return false;
}
this->Separation = SeparationWarning;
}
else if(token->type == cmListFileLexer_Token_Identifier ||
token->type == cmListFileLexer_Token_ArgumentUnquoted)
{
this->AddArgument(token, cmListFileArgument::Unquoted);
if(!this->AddArgument(token, cmListFileArgument::Unquoted))
{
return false;
}
this->Separation = SeparationWarning;
}
else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
{
this->AddArgument(token, cmListFileArgument::Quoted);
if(!this->AddArgument(token, cmListFileArgument::Quoted))
{
return false;
}
this->Separation = SeparationWarning;
}
else if(token->type == cmListFileLexer_Token_ArgumentBracket)
{
if(!this->AddArgument(token, cmListFileArgument::Bracket))
{
return false;
}
this->Separation = SeparationError;
}
else if(token->type == cmListFileLexer_Token_CommentBracket)
{
this->Separation = SeparationError;
}
else
{
// Error.
......@@ -351,42 +379,32 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
}
//----------------------------------------------------------------------------
void cmListFileParser::AddArgument(cmListFileLexer_Token* token,
bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim)
{
cmListFileArgument a(token->text, delim, this->FileName, token->line);
this->Function.Arguments.push_back(a);
if(delim == cmListFileArgument::Unquoted)
{
// Warn about a future behavior change.
const char* c = a.Value.c_str();
if(*c++ == '[')
{
while(*c == '=')
{ ++c; }
if(*c == '[')
{
cmOStringStream m;
m << "Syntax Warning in cmake code at\n"
<< " " << this->FileName << ":" << token->line << ":"
<< token->column << "\n"
<< "A future version of CMake may treat unquoted argument:\n"
<< " " << a.Value << "\n"
<< "as an opening long bracket. Double-quote the argument.";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str());
}
}
}
if(this->Separation == SeparationOkay)
{
return;
return true;
}
bool isError = (this->Separation == SeparationError ||
delim == cmListFileArgument::Bracket);
cmOStringStream m;
m << "Syntax Warning in cmake code at\n"
m << "Syntax " << (isError? "Error":"Warning") << " in cmake code at\n"
<< " " << this->FileName << ":" << token->line << ":"
<< token->column << "\n"
<< "Argument not separated from preceding token by whitespace.";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str());
if(isError)
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str().c_str());
return false;
}
else
{
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str());
return true;
}
}
//----------------------------------------------------------------------------
......
......@@ -28,7 +28,8 @@ struct cmListFileArgument
enum Delimiter
{
Unquoted,
Quoted
Quoted,
Bracket
};
cmListFileArgument(): Value(), Delim(Unquoted), FilePath(0), Line(0) {}
cmListFileArgument(const cmListFileArgument& r):
......
This diff is collapsed.
......@@ -22,7 +22,10 @@ typedef enum cmListFileLexer_Type_e
cmListFileLexer_Token_ParenRight,
cmListFileLexer_Token_ArgumentUnquoted,
cmListFileLexer_Token_ArgumentQuoted,
cmListFileLexer_Token_ArgumentBracket,
cmListFileLexer_Token_CommentBracket,
cmListFileLexer_Token_BadCharacter,
cmListFileLexer_Token_BadBracket,
cmListFileLexer_Token_BadString
} cmListFileLexer_Type;
......
......@@ -42,6 +42,8 @@ Modify cmListFileLexer.c:
struct cmListFileLexer_s
{
cmListFileLexer_Token token;
int bracket;
int comment;
int line;
int column;
int size;
......@@ -75,22 +77,57 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer);
%option noyywrap
%pointer
%x STRING
%x BRACKET
%x BRACKETEND
%x COMMENT
MAKEVAR \$\([A-Za-z0-9_]*\)
UNQUOTED ([^ \t\r\n\(\)#\\\"]|\\.)
LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t])*\"
UNQUOTED ([^ \t\r\n\(\)#\\\"[=]|\\.)
LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
%%
\n {
<INITIAL,COMMENT>\n {
lexer->token.type = cmListFileLexer_Token_Newline;
cmListFileLexerSetToken(lexer, yytext, yyleng);
++lexer->line;
lexer->column = 1;
BEGIN(INITIAL);
return 1;
}
#.* {
#?\[=*\[\n? {
const char* bracket = yytext;
lexer->comment = yytext[0] == '#';
if(lexer->comment)
{
lexer->token.type = cmListFileLexer_Token_CommentBracket;
bracket += 1;
}
else
{
lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
}
cmListFileLexerSetToken(lexer, "", 0);
lexer->bracket = (int)(strchr(bracket+1, '[') - bracket);
if(yytext[yyleng-1] == '\n')
{
++lexer->line;
lexer->column = 1;
}
else
{
lexer->column += yyleng;
}
BEGIN(BRACKET);
}
# {
lexer->column += yyleng;
BEGIN(COMMENT);
}
<COMMENT>.* {
lexer->column += yyleng;
}
......@@ -115,14 +152,57 @@ LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t])*\"
return 1;
}
({UNQUOTED})({UNQUOTED})* {
<BRACKET>\]=* {
/* Handle ]]====]=======]*/
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
if(yyleng == lexer->bracket)
{
BEGIN(BRACKETEND);
}
}
<BRACKETEND>\] {
lexer->column += yyleng;
/* Erase the partial bracket from the token. */
lexer->token.length -= lexer->bracket;
lexer->token.text[lexer->token.length] = 0;
BEGIN(INITIAL);
return 1;
}
<BRACKET>([^]\n])+ {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
}
<BRACKET,BRACKETEND>\n {
cmListFileLexerAppend(lexer, yytext, yyleng);
++lexer->line;
lexer->column = 1;
BEGIN(BRACKET);
}
<BRACKET,BRACKETEND>. {
cmListFileLexerAppend(lexer, yytext, yyleng);
lexer->column += yyleng;
BEGIN(BRACKET);
}
<BRACKET,BRACKETEND><<EOF>> {
lexer->token.type = cmListFileLexer_Token_BadBracket;
BEGIN(INITIAL);
return 1;
}
({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
return 1;
}
({MAKEVAR}|{UNQUOTED})({LEGACY})* {
({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
cmListFileLexerSetToken(lexer, yytext, yyleng);
lexer->column += yyleng;
......@@ -513,7 +593,10 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
case cmListFileLexer_Token_ParenRight: return "right paren";
case cmListFileLexer_Token_ArgumentUnquoted: return "unquoted argument";
case cmListFileLexer_Token_ArgumentQuoted: return "quoted argument";
case cmListFileLexer_Token_ArgumentBracket: return "bracket argument";
case cmListFileLexer_Token_CommentBracket: return "bracket comment";
case cmListFileLexer_Token_BadCharacter: return "bad character";
case cmListFileLexer_Token_BadBracket: return "unterminated bracket";
case cmListFileLexer_Token_BadString: return "unterminated string";
}
return "unknown token";
......
......@@ -2867,6 +2867,12 @@ bool cmMakefile::ExpandArguments(
outArgs.reserve(inArgs.size());
for(i = inArgs.begin(); i != inArgs.end(); ++i)
{
// No expansion in a bracket argument.
if(i->Delim == cmListFileArgument::Bracket)
{
outArgs.push_back(i->Value);
continue;
}
// Expand the variables in the argument.
value = i->Value;
this->ExpandVariablesInString(value, false, false, false,
......
CommandTabs.cmake whitespace=-tab-in-indent
StringCRLF.cmake whitespace=cr-at-eol -crlf
BracketCRLF.cmake whitespace=cr-at-eol -crlf
message([[1 ${var} \n 4]])
message([==[1 ]==] [=[
${var} \n 4]==]=])
-- Bracket Argument 1
-- Bracket Argument 2
message(STATUS [[Bracket Argument 1]] #[[Bracket Comment 1]])
message(STATUS #[[Bracket Comment 2]] [[Bracket Argument 2]])
CMake Error at BracketBackslash.cmake:1 \(message\):
a\\
b
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$
message(FATAL_ERROR [==[a\
b]==])
if([[
]] STREQUAL "" AND
[[a
b]] STREQUAL "a\nb")
message("CRLF->LF worked")
else()
message(FATAL_ERROR "CRLF->LF failed")
endif()
-- The above FATAL_ERROR did not occur.
#[=[
#]]
message(FATAL_ERROR "This is commented out.")
#]==]=]
message(STATUS "The above FATAL_ERROR did not occur.")
CMake Error at BracketComment1.cmake:2 \(message\):
This is not commented out.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
##[[
message(FATAL_ERROR "This is not commented out.")
#]]
CMake Error at BracketComment2.cmake:2 \(message\):
This is not commented out.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
# [[
message(FATAL_ERROR "This is not commented out.")
#]]
-- The above FATAL_ERROR did not occur.
#[[Text on opening line
message(FATAL_ERROR "This is commented out.")
#]=]]
message(STATUS "The above FATAL_ERROR did not occur.")
CMake Error: Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketComment4.cmake:3:
Parse error. Expected a newline, got identifier with text "message".
CMake Error at CMakeLists.txt:3 \(include\):
include could not find load file:
BracketComment4.cmake
#[[
message(FATAL_ERROR "This is commented out.")
#]] message(STATUS "This command not allowed here")
-- The above FATAL_ERROR did not occur.
#[[
message(FATAL_ERROR "This is commented out.")
#]] #[[
message(FATAL_ERROR "This is commented out.")
#]] #message(FATAL_ERROR "This is commented out.")
message(STATUS "The above FATAL_ERROR did not occur.")
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace0.cmake:1:27
Argument not separated from preceding token by whitespace.
message(STATUS [[bracket]]unquoted)
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace1.cmake:1:24
Argument not separated from preceding token by whitespace.
message(STATUS "string"[[bracket]])
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace2.cmake:1:44
Argument not separated from preceding token by whitespace.
message(STATUS "string"#[[bracket comment]][[bracket]])
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace3.cmake:1:45
Argument not separated from preceding token by whitespace.
message(STATUS "string" #[[bracket comment]][[bracket]])
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace4.cmake:1:44
Argument not separated from preceding token by whitespace.
message(STATUS "string"#[[bracket comment]]"string")
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
.*/Tests/RunCMake/Syntax/BracketNoSpace5.cmake:1:45
Argument not separated from preceding token by whitespace.
message(STATUS "string" #[[bracket comment]]"string")
CMake Error: Error in cmake code at
.*/Tests/RunCMake/Syntax/CommandError2.cmake:1:
Parse error. Expected a command name, got bracket argument with text "oops-not-a-comment".
CMake Error at CMakeLists.txt:3 \(include\):
include could not find load file:
CommandError2.cmake
message("Example Message") [[oops-not-a-comment]]
-- \(unquoted\)
-- \(quoted\)
-- \(bracket\)
message(STATUS (unquoted))
message(STATUS ("quoted"))
message(STATUS ([[bracket]]))
CMake Warning \(dev\) at CMakeLists.txt:3 \(include\):
Syntax Warning in cmake code at
.*/Tests/RunCMake/Syntax/BracketWarn.cmake:1:16
.*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:1:26
A future version of CMake may treat unquoted argument:
\[\[
as an opening long bracket. Double-quote the argument.
Argument not separated from preceding token by whitespace.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at CMakeLists.txt:3 \(include\):
Syntax Warning in cmake code at
.*/Tests/RunCMake/Syntax/BracketWarn.cmake:1:19
A future version of CMake may treat unquoted argument:
.*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:2:26
\[=\[
as an opening long bracket. Double-quote the argument.
Argument not separated from preceding token by whitespace.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at CMakeLists.txt:3 \(include\):
Syntax Warning in cmake code at
.*/Tests/RunCMake/Syntax/BracketWarn.cmake:1:27
CMake Error at CMakeLists.txt:3 \(include\):
Syntax Error in cmake code at
A future version of CMake may treat unquoted argument:
.*/Tests/RunCMake/Syntax/ParenNoSpace1.cmake:3:29
\[==\[x
as an opening long bracket. Double-quote the argument.
This warning is for project developers. Use -Wno-dev to suppress it.
Argument not separated from preceding token by whitespace.
message(STATUS (unquoted)unquoted)
message(STATUS ("quoted")"quoted")
message(STATUS ([[bracket]])[[bracket]])
message(STATUS unquoted(unquoted))
message(STATUS "quoted"("quoted"))
message(STATUS [[bracket]]([[bracket]]))
......@@ -11,6 +11,7 @@ run_cmake(CommandNewlines)
run_cmake(CommandComments)
run_cmake(CommandError0)
run_cmake(CommandError1)
run_cmake(CommandError2)
run_cmake(String0)
run_cmake(String1)
run_cmake(StringCRLF)
......@@ -18,8 +19,29 @@ run_cmake(StringNoSpace)
run_cmake(OneLetter)
run_cmake(Unquoted0)
run_cmake(Unquoted1)
run_cmake(ParenNoSpace)
run_cmake(Bracket0)
run_cmake(Bracket1)
run_cmake(Bracket2)
run_cmake(BracketBackslash)
run_cmake(BracketCRLF)
run_cmake(BracketComment0)
run_cmake(BracketComment1)
run_cmake(BracketComment2)
run_cmake(BracketComment3)
run_cmake(BracketComment4)
run_cmake(BracketComment5)
run_cmake(BracketNoSpace0)
run_cmake(BracketNoSpace1)
run_cmake(BracketNoSpace2)
run_cmake(BracketNoSpace3)
run_cmake(BracketNoSpace4)
run_cmake(BracketNoSpace5)
run_cmake(ParenNoSpace0)
run_cmake(ParenNoSpace1)
run_cmake(ParenNoSpace2)
run_cmake(UnterminatedCall1)
run_cmake(UnterminatedCall2)
run_cmake(UnterminatedString)
run_cmake(BracketWarn)
run_cmake(UnterminatedBracket0)
run_cmake(UnterminatedBracket1)
run_cmake(UnterminatedBracketComment)
CMake Error: Error in cmake code at
.*/Syntax/UnterminatedBracket0.cmake:2:
Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\)
".
CMake Error at CMakeLists.txt:3 \(include\):
include could not find load file:
UnterminatedBracket0.cmake$
CMake Error: Error in cmake code at
.*/Syntax/UnterminatedBracket1.cmake:2:
Parse error. Function missing ending "\)". Instead found unterminated bracket with text "\]\]\)
".
CMake Error at CMakeLists.txt:3 \(include\):
include could not find load file:
UnterminatedBracket1.cmake$
CMake Error: Error in cmake code at
.*/Syntax/UnterminatedBracketComment.cmake:1:
Parse error. Expected a command name, got unterminated bracket with text "#\]\]
".
CMake Error at CMakeLists.txt:3 \(include\):
include could not find load file:
UnterminatedBracketComment.cmake
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment