From 0efc383752425c5ba19e6389da5235584e2f1170 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Sun, 24 Oct 2010 11:51:20 -0700 Subject: [PATCH] remove command keyword, convert to variable binding --- README.markdown | 9 ++++++--- manifest_parser.h | 57 +++++++++++++++++++++++++++---------------------------- ninja_test.cc | 14 +++++++------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/README.markdown b/README.markdown index da79400..5a83e79 100644 --- a/README.markdown +++ b/README.markdown @@ -43,10 +43,13 @@ project, while `rule` statements describe how to generate the files within a given edge of the graph. ### Rules -Here's an example of a simple rule for compiling C code. + +Rules begin with the `rule` keyword and a name for the rule, followed +by an indented set of `key = val` lines. Here's an example of a +simple rule for compiling C code. rule cc - command gcc -c $in -o $out + command = gcc -c $in -o $out This declares a new rule named `cc`, along with the command to run. `Variables` begin with a `$` and are described more fully later, but @@ -75,7 +78,7 @@ build files readable (debuggable), Ninja supports declaring bindings Can be used in a rule like this: rule cc - command gcc $cflags -c $in -o $out + command = gcc $cflags -c $in -o $out Variables might better be called "bindings", in that a given variable cannot be changed, only shadowed. Within a larger Ninja project, diff --git a/manifest_parser.h b/manifest_parser.h index f0ebd5c..a46f16c 100644 --- a/manifest_parser.h +++ b/manifest_parser.h @@ -7,7 +7,6 @@ struct Token { NONE, IDENT, RULE, - COMMAND, BUILD, NEWLINE, EQUALS, @@ -23,7 +22,6 @@ struct Token { switch (type_) { case IDENT: return "'" + extra_ + "'"; case RULE: return "'rule'"; - case COMMAND: return "'command'"; case BUILD: return "'build'"; case NEWLINE: return "newline"; case EQUALS: return "'='"; @@ -190,8 +188,6 @@ Token::Type Parser::PeekToken() { } if (token_.extra_ == "rule") token_.type_ = Token::RULE; - else if (token_.extra_ == "command") - token_.type_ = Token::COMMAND; else if (token_.extra_ == "build") token_.type_ = Token::BUILD; else @@ -228,7 +224,7 @@ struct ManifestParser { bool Parse(const string& input, string* err); bool ParseRule(string* err); - bool ParseLet(string* err); + bool ParseLet(string* key, string* val, string* err); bool ParseEdge(string* err); string ExpandFile(const string& file); @@ -276,10 +272,19 @@ bool ManifestParser::Parse(const string& input, string* err) { if (!ParseEdge(err)) return false; break; - case Token::IDENT: - if (!ParseLet(err)) + case Token::IDENT: { + string name, value; + if (!ParseLet(&name, &value, err)) return false; + + state_->AddBinding(name, value); + if (name == "builddir") { + builddir_ = value; + if (!builddir_.empty() && builddir_[builddir_.size() - 1] != '/') + builddir_.push_back('/'); + } break; + } case Token::TEOF: continue; default: @@ -304,39 +309,33 @@ bool ManifestParser::ParseRule(string* err) { if (parser_.PeekToken() == Token::INDENT) { parser_.ConsumeToken(); - if (!parser_.ExpectToken(Token::COMMAND, err)) - return false; - if (!parser_.ReadToNewline(&command, err)) - return false; + while (parser_.PeekToken() != Token::OUTDENT) { + string key, val; + if (!ParseLet(&key, &val, err)) + return false; - if (!parser_.ExpectToken(Token::OUTDENT, err)) - return false; + if (key != "command") { + *err = "expected 'command'"; + return false; + } + command = val; + } + parser_.ConsumeToken(); } - state_->AddRule(name, command); + if (!command.empty()) + state_->AddRule(name, command); return true; } -bool ManifestParser::ParseLet(string* err) { - string name; - if (!parser_.ReadIdent(&name)) +bool ManifestParser::ParseLet(string* name, string* value, string* err) { + if (!parser_.ReadIdent(name)) return parser_.Error("expected variable name", err); - if (!parser_.ExpectToken(Token::EQUALS, err)) return false; - - string value; - if (!parser_.ReadToNewline(&value, err)) + if (!parser_.ReadToNewline(value, err)) return false; - - state_->AddBinding(name, value); - if (name == "builddir") { - builddir_ = value; - if (!builddir_.empty() && builddir_[builddir_.size() - 1] != '/') - builddir_.push_back('/'); - } - return true; } diff --git a/ninja_test.cc b/ninja_test.cc index 2c1c4d5..b4b6665 100644 --- a/ninja_test.cc +++ b/ninja_test.cc @@ -22,10 +22,10 @@ TEST(Parser, Rules) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, "rule cat\n" -" command cat @in > $out\n" +" command = cat @in > $out\n" "\n" "rule date\n" -" command date > $out\n" +" command = date > $out\n" "\n" "build result: cat in_1.cc in-2.O\n")); @@ -39,7 +39,7 @@ TEST(Parser, Variables) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, "rule link\n" -" command ld $extra $with_under -o $out @in\n" +" command = ld $extra $with_under -o $out @in\n" "\n" "extra = -pthread\n" "with_under = -under\n" @@ -54,7 +54,7 @@ TEST(Parser, Continuation) { State state; ASSERT_NO_FATAL_FAILURE(AssertParse(&state, "rule link\n" -" command foo bar \\\n" +" command = foo bar \\\n" " baz\n" "\n" "build a: link c \\\n" @@ -114,7 +114,7 @@ TEST(Parser, Errors) { { ManifestParser parser(&state); string err; - EXPECT_FALSE(parser.Parse("rule cat\n command cat ok\n" + EXPECT_FALSE(parser.Parse("rule cat\n command = cat ok\n" "build x: cat \\\n :\n", &err)); EXPECT_EQ("line 4, col 2: expected newline, got ':'", err); @@ -126,7 +126,7 @@ TEST(Parser, BuildDir) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state, "builddir = out\n" "rule cat\n" -" command cat @in > $out\n" +" command = cat @in > $out\n" "build @bin: cat @a.o\n" "build @a.o: cat a.cc\n")); state.stat_cache()->Dump(); @@ -179,7 +179,7 @@ struct StateTestWithBuiltinRules : public testing::Test { StateTestWithBuiltinRules() { AssertParse(&state_, "rule cat\n" -" command cat @in > $out\n"); +" command = cat @in > $out\n"); } Node* GetNode(const string& path) { -- 2.7.4