diff options
author | Evan Martin <martine@danga.com> | 2012-01-29 16:46:52 (GMT) |
---|---|---|
committer | Evan Martin <martine@danga.com> | 2012-01-29 16:46:52 (GMT) |
commit | 33206906ef36d7bebfefb9a8a798217ee6851df4 (patch) | |
tree | 970d5c7fb9207ec96beff9d9fdfcf60c60a06e0d | |
parent | c8faeaa5a1c5e2f5e75d0f1be19c70479475c5ce (diff) | |
parent | 2e481086ad7337bb868327f12ffd317dc5143a3e (diff) | |
download | Ninja-33206906ef36d7bebfefb9a8a798217ee6851df4.zip Ninja-33206906ef36d7bebfefb9a8a798217ee6851df4.tar.gz Ninja-33206906ef36d7bebfefb9a8a798217ee6851df4.tar.bz2 |
Merge pull request #210 from syntheticpp/colon-escape
add colon escaping
-rw-r--r-- | src/lexer.cc | 72 | ||||
-rw-r--r-- | src/lexer.h | 4 | ||||
-rw-r--r-- | src/lexer.in.cc | 24 | ||||
-rw-r--r-- | src/lexer_test.cc | 4 | ||||
-rw-r--r-- | src/parsers.cc | 1 | ||||
-rw-r--r-- | src/parsers_test.cc | 37 |
6 files changed, 115 insertions, 27 deletions
diff --git a/src/lexer.cc b/src/lexer.cc index 5bc467b..9e4392c 100644 --- a/src/lexer.cc +++ b/src/lexer.cc @@ -90,6 +90,26 @@ const char* Lexer::TokenName(Token t) { return NULL; // not reached } +const char* Lexer::TokenErrorHint(Token t) { + switch (t) { + case ERROR: return ""; + case BUILD: return ""; + case COLON: return " ($ also escapes ':')"; + case DEFAULT: return ""; + case EQUALS: return ""; + case IDENT: return ""; + case INCLUDE: return ""; + case INDENT: return ""; + case NEWLINE: return ""; + case PIPE2: return ""; + case PIPE: return ""; + case RULE: return ""; + case SUBNINJA: return ""; + case TEOF: return ""; + } + return ""; +} + void Lexer::UnreadToken() { ofs_ = last_token_; } @@ -606,7 +626,7 @@ bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) { } ++p; yych = *p; - goto yy118; + goto yy120; yy91: { eval->AddText(StringPiece(start, p - start)); @@ -629,7 +649,7 @@ yy94: ++p; if ((yych = *p) <= '/') { if (yych <= ' ') { - if (yych == '\n') goto yy107; + if (yych == '\n') goto yy109; if (yych <= 0x1F) goto yy98; goto yy100; } else { @@ -643,17 +663,21 @@ yy94: } } else { if (yych <= '^') { - if (yych <= '9') goto yy104; - if (yych <= '@') goto yy98; - if (yych <= 'Z') goto yy104; - goto yy98; + if (yych <= ':') { + if (yych <= '9') goto yy104; + goto yy106; + } else { + if (yych <= '@') goto yy98; + if (yych <= 'Z') goto yy104; + goto yy98; + } } else { if (yych <= '`') { if (yych <= '_') goto yy104; goto yy98; } else { if (yych <= 'z') goto yy104; - if (yych <= '{') goto yy106; + if (yych <= '{') goto yy108; goto yy98; } } @@ -690,56 +714,62 @@ yy102: yy104: ++p; yych = *p; - goto yy116; + goto yy118; yy105: { eval->AddSpecial(StringPiece(start + 1, p - start - 1)); continue; } yy106: + ++p; + { + eval->AddText(StringPiece(":", 1)); + continue; + } +yy108: yych = *(q = ++p); if (yybm[0+yych] & 32) { - goto yy110; + goto yy112; } goto yy99; -yy107: +yy109: ++p; yych = *p; if (yybm[0+yych] & 16) { - goto yy107; + goto yy109; } { continue; } -yy110: +yy112: ++p; yych = *p; if (yybm[0+yych] & 32) { - goto yy110; + goto yy112; } - if (yych == '}') goto yy113; + if (yych == '}') goto yy115; p = q; goto yy99; -yy113: +yy115: ++p; { eval->AddSpecial(StringPiece(start + 2, p - start - 3)); continue; } -yy115: +yy117: ++p; yych = *p; -yy116: +yy118: if (yybm[0+yych] & 64) { - goto yy115; + goto yy117; } goto yy105; -yy117: +yy119: ++p; yych = *p; -yy118: +yy120: if (yybm[0+yych] & 128) { - goto yy117; + goto yy119; } goto yy91; } diff --git a/src/lexer.h b/src/lexer.h index c872b98..75c1b2f 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -46,6 +46,10 @@ struct Lexer { /// Return a human-readable form of a token, used in error messages. static const char* TokenName(Token t); + + /// Return a human-readable token hint, used in error messages. + static const char* TokenErrorHint(Token t); + /// Start parsing some input. void Start(StringPiece filename, StringPiece input); diff --git a/src/lexer.in.cc b/src/lexer.in.cc index 6c00dbd..28a5bdf 100644 --- a/src/lexer.in.cc +++ b/src/lexer.in.cc @@ -89,6 +89,26 @@ const char* Lexer::TokenName(Token t) { return NULL; // not reached } +const char* Lexer::TokenErrorHint(Token t) { + switch (t) { + case ERROR: return ""; + case BUILD: return ""; + case COLON: return " ($ also escapes ':')"; + case DEFAULT: return ""; + case EQUALS: return ""; + case IDENT: return ""; + case INCLUDE: return ""; + case INDENT: return ""; + case NEWLINE: return ""; + case PIPE2: return ""; + case PIPE: return ""; + case RULE: return ""; + case SUBNINJA: return ""; + case TEOF: return ""; + } + return ""; +} + void Lexer::UnreadToken() { ofs_ = last_token_; } @@ -214,6 +234,10 @@ bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) { eval->AddSpecial(StringPiece(start + 1, p - start - 1)); continue; } + "$:" { + eval->AddText(StringPiece(":", 1)); + continue; + } "$". { last_token_ = start; return Error("bad $-escape (literal $ must be written as $$)", err); diff --git a/src/lexer_test.cc b/src/lexer_test.cc index 1c5894e..5795e5e 100644 --- a/src/lexer_test.cc +++ b/src/lexer_test.cc @@ -29,12 +29,12 @@ TEST(Lexer, ReadVarValue) { } TEST(Lexer, ReadEvalStringEscapes) { - Lexer lexer("$ $$ab $\ncde\n"); + Lexer lexer("$ $$ab c$: $\ncde\n"); EvalString eval; string err; EXPECT_TRUE(lexer.ReadVarValue(&eval, &err)); EXPECT_EQ("", err); - EXPECT_EQ("[ $ab cde]", + EXPECT_EQ("[ $ab c: cde]", eval.Serialize()); } diff --git a/src/parsers.cc b/src/parsers.cc index c1badd8..5d347b2 100644 --- a/src/parsers.cc +++ b/src/parsers.cc @@ -313,6 +313,7 @@ bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) { if (token != expected) { string message = string("expected ") + Lexer::TokenName(expected); message += string(", got ") + Lexer::TokenName(token); + message += Lexer::TokenErrorHint(expected); return lexer_.Error(message, err); } return true; diff --git a/src/parsers_test.cc b/src/parsers_test.cc index f3ac517..2a30a83 100644 --- a/src/parsers_test.cc +++ b/src/parsers_test.cc @@ -377,14 +377,30 @@ TEST_F(ParserTest, Errors) { ManifestParser parser(&state, NULL); string err; EXPECT_FALSE(parser.ParseTest("rule cat\n" - " command = cat\nbuild $: cat foo\n", + " command = cat\n" + "build $.: cat foo\n", &err)); EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n" - "build $: cat foo\n" + "build $.: cat foo\n" " ^ near here" , err); } + + { + State state; + ManifestParser parser(&state, NULL); + string err; + EXPECT_FALSE(parser.ParseTest("rule cat\n" + " command = cat\n" + "build $: cat foo\n", + &err)); + EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n" + "build $: cat foo\n" + " ^ near here" + , err); + } + { State state; ManifestParser parser(&state, NULL); @@ -413,10 +429,10 @@ TEST_F(ParserTest, Errors) { ManifestParser parser(&state, NULL); string err; EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n" - "build $: cc bar.cc\n", + "build $.: cc bar.cc\n", &err)); EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n" - "build $: cc bar.cc\n" + "build $.: cc bar.cc\n" " ^ near here" , err); } @@ -425,6 +441,19 @@ TEST_F(ParserTest, Errors) { State state; ManifestParser parser(&state, NULL); string err; + EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n" + "build $: cc bar.cc\n", + &err)); + EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n" + "build $: cc bar.cc\n" + " ^ near here" + , err); + } + + { + State state; + ManifestParser parser(&state, NULL); + string err; EXPECT_FALSE(parser.ParseTest("default\n", &err)); EXPECT_EQ("input:1: expected target name\n" |