File src/make/MakeLexerData.hpp changed (mode: 100644) (index bfd30e2..d7c710f) |
... |
... |
struct MakeLexerData : LexerData |
31 |
31 |
{ |
{ |
32 |
32 |
// Type of nesting. |
// Type of nesting. |
33 |
33 |
enum { |
enum { |
34 |
|
FunctionNesting, // Function nesting. |
|
35 |
|
ArgumentNesting, // Function argument nesting. |
|
|
34 |
|
FunctionNesting, // Function nesting. |
|
35 |
|
ArgumentNesting, // Function argument nesting. |
|
36 |
|
EvalArgumentNesting, // `$$(...)` inside a call. |
36 |
37 |
}; |
}; |
37 |
38 |
|
|
38 |
39 |
std::size_t offset = 0U; // Byte offset in the input. |
std::size_t offset = 0U; // Byte offset in the input. |
|
... |
... |
struct MakeLexerData : LexerData |
51 |
52 |
// Whether whitespace token might be needed before the next token. |
// Whether whitespace token might be needed before the next token. |
52 |
53 |
bool fakeWSIsNeeded = false; |
bool fakeWSIsNeeded = false; |
53 |
54 |
// Keeps track of function nesting (where keywords stop being keywords). |
// Keeps track of function nesting (where keywords stop being keywords). |
54 |
|
std::vector<bool> nesting; |
|
|
55 |
|
std::vector<unsigned char> nesting; |
55 |
56 |
|
|
56 |
57 |
MakeParseData *pd; // Link to Make-specific state of the parser. |
MakeParseData *pd; // Link to Make-specific state of the parser. |
57 |
58 |
|
|
File src/make/make-lexer.flex changed (mode: 100644) (index 5e1928a..bf02ee3) |
82 |
82 |
|
|
83 |
83 |
using namespace makestypes; |
using namespace makestypes; |
84 |
84 |
|
|
85 |
|
// Convenience definition for token() funciton's argument. |
|
|
85 |
|
// Convenience definition for token() function's argument. |
86 |
86 |
enum { NeedFakeWS = 1 }; |
enum { NeedFakeWS = 1 }; |
87 |
87 |
|
|
88 |
88 |
// Performs additional operations on returning a token. |
// Performs additional operations on returning a token. |
|
... |
... |
NL \n|\r|\r\n |
257 |
257 |
yyextra->nesting.push_back(MakeLexerData::FunctionNesting); |
yyextra->nesting.push_back(MakeLexerData::FunctionNesting); |
258 |
258 |
return token(CALL_PREFIX, yylval, yyextra); |
return token(CALL_PREFIX, yylval, yyextra); |
259 |
259 |
} |
} |
|
260 |
|
"$$(" { |
|
261 |
|
if (shouldInsertFakeWS(yylval, yyextra)) { |
|
262 |
|
return FAKE_TOKEN(WS); |
|
263 |
|
} |
|
264 |
|
if (!yyextra->nesting.empty()) { |
|
265 |
|
yyextra->nesting.push_back(MakeLexerData::EvalArgumentNesting); |
|
266 |
|
} |
|
267 |
|
return token(CHARS, yylval, yyextra, NeedFakeWS); |
|
268 |
|
} |
260 |
269 |
$. return token(VAR, yylval, yyextra); |
$. return token(VAR, yylval, yyextra); |
261 |
270 |
"(" { |
"(" { |
262 |
271 |
if (shouldInsertFakeWS(yylval, yyextra)) { |
if (shouldInsertFakeWS(yylval, yyextra)) { |
|
... |
... |
$. return token(VAR, yylval, yyextra); |
271 |
280 |
if (yyextra->nesting.empty()) { |
if (yyextra->nesting.empty()) { |
272 |
281 |
return token(')', yylval, yyextra); |
return token(')', yylval, yyextra); |
273 |
282 |
} |
} |
274 |
|
if (yyextra->nesting.back() == MakeLexerData::ArgumentNesting) { |
|
275 |
|
yyextra->nesting.pop_back(); |
|
|
283 |
|
|
|
284 |
|
int what = yyextra->nesting.back(); |
|
285 |
|
yyextra->nesting.pop_back(); |
|
286 |
|
|
|
287 |
|
if (what == MakeLexerData::ArgumentNesting) { |
276 |
288 |
return token(')', yylval, yyextra, NeedFakeWS); |
return token(')', yylval, yyextra, NeedFakeWS); |
277 |
289 |
} |
} |
278 |
|
yyextra->nesting.pop_back(); |
|
|
290 |
|
if (what == MakeLexerData::EvalArgumentNesting) { |
|
291 |
|
return token(CHARS, yylval, yyextra, NeedFakeWS); |
|
292 |
|
} |
279 |
293 |
return token(CALL_SUFFIX, yylval, yyextra, NeedFakeWS); |
return token(CALL_SUFFIX, yylval, yyextra, NeedFakeWS); |
280 |
294 |
} |
} |
281 |
295 |
"}" { |
"}" { |
File tests/make/make-parser.cpp changed (mode: 100644) (index e0fdc82..9fe7b1f) |
... |
... |
TEST_CASE("Variables are parsed in a Makefile", "[make][parser]") |
169 |
169 |
CHECK(makeIsParsed("target: )()(")); |
CHECK(makeIsParsed("target: )()(")); |
170 |
170 |
|
|
171 |
171 |
Tree tree = parseMake("target: $$($1.name)"); |
Tree tree = parseMake("target: $$($1.name)"); |
172 |
|
CHECK(findNode(tree, Type::UserTypes, "$$") != nullptr); |
|
173 |
172 |
CHECK(findNode(tree, Type::UserTypes, "$1") != nullptr); |
CHECK(findNode(tree, Type::UserTypes, "$1") != nullptr); |
|
173 |
|
// This isn't a variable, it's an escape sequence. |
|
174 |
|
CHECK(findNode(tree, Type::UserTypes, "$$") == nullptr); |
174 |
175 |
} |
} |
175 |
176 |
|
|
176 |
177 |
TEST_CASE("Functions are parsed in a Makefile", "[make][parser]") |
TEST_CASE("Functions are parsed in a Makefile", "[make][parser]") |