Factor out a base class of ManifestParser

Create a Parser base class that holds parser functionality not specific
to the build manifest file format.  This will allow it to be re-used for
other parsers later.
This commit is contained in:
Brad King 2015-07-02 13:12:44 -04:00
parent 215a190a57
commit d718808392
5 changed files with 105 additions and 53 deletions

View File

@ -504,6 +504,7 @@ for name in ['build',
'line_printer', 'line_printer',
'manifest_parser', 'manifest_parser',
'metrics', 'metrics',
'parser',
'state', 'state',
'string_piece_util', 'string_piece_util',
'util', 'util',

View File

@ -18,41 +18,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include <vector>
#include "disk_interface.h"
#include "graph.h" #include "graph.h"
#include "metrics.h"
#include "state.h" #include "state.h"
#include "util.h" #include "util.h"
#include "version.h" #include "version.h"
ManifestParser::ManifestParser(State* state, FileReader* file_reader, ManifestParser::ManifestParser(State* state, FileReader* file_reader,
ManifestParserOptions options) ManifestParserOptions options)
: state_(state), file_reader_(file_reader), : Parser(state, file_reader),
options_(options), quiet_(false) { options_(options), quiet_(false) {
env_ = &state->bindings_; env_ = &state->bindings_;
} }
bool ManifestParser::Load(const string& filename, string* err, Lexer* parent) {
METRIC_RECORD(".ninja parse");
string contents;
string read_err;
if (file_reader_->ReadFile(filename, &contents, &read_err) != FileReader::Okay) {
*err = "loading '" + filename + "': " + read_err;
if (parent)
parent->Error(string(*err), err);
return false;
}
// The lexer needs a nul byte at the end of its input, to know when it's done.
// It takes a StringPiece, and StringPiece's string constructor uses
// string::data(). data()'s return value isn't guaranteed to be
// null-terminated (although in practice - libc++, libstdc++, msvc's stl --
// it is, and C++11 demands that too), so add an explicit nul byte.
contents.resize(contents.size() + 1);
return Parse(filename, contents, err);
}
bool ManifestParser::Parse(const string& filename, const string& input, bool ManifestParser::Parse(const string& filename, const string& input,
string* err) { string* err) {
lexer_.Start(filename, input); lexer_.Start(filename, input);
@ -434,14 +411,3 @@ bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
return true; return true;
} }
bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) {
Lexer::Token token = lexer_.ReadToken();
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;
}

View File

@ -15,16 +15,10 @@
#ifndef NINJA_MANIFEST_PARSER_H_ #ifndef NINJA_MANIFEST_PARSER_H_
#define NINJA_MANIFEST_PARSER_H_ #define NINJA_MANIFEST_PARSER_H_
#include <string> #include "parser.h"
using namespace std;
#include "lexer.h"
struct BindingEnv; struct BindingEnv;
struct EvalString; struct EvalString;
struct FileReader;
struct State;
enum DupeEdgeAction { enum DupeEdgeAction {
kDupeEdgeActionWarn, kDupeEdgeActionWarn,
@ -45,13 +39,10 @@ struct ManifestParserOptions {
}; };
/// Parses .ninja files. /// Parses .ninja files.
struct ManifestParser { struct ManifestParser : public Parser {
ManifestParser(State* state, FileReader* file_reader, ManifestParser(State* state, FileReader* file_reader,
ManifestParserOptions options = ManifestParserOptions()); ManifestParserOptions options = ManifestParserOptions());
/// Load and parse a file.
bool Load(const string& filename, string* err, Lexer* parent = NULL);
/// Parse a text string of input. Used by tests. /// Parse a text string of input. Used by tests.
bool ParseTest(const string& input, string* err) { bool ParseTest(const string& input, string* err) {
quiet_ = true; quiet_ = true;
@ -72,14 +63,7 @@ private:
/// Parse either a 'subninja' or 'include' line. /// Parse either a 'subninja' or 'include' line.
bool ParseFileInclude(bool new_scope, string* err); bool ParseFileInclude(bool new_scope, string* err);
/// If the next token is not \a expected, produce an error string
/// saying "expected foo, got bar".
bool ExpectToken(Lexer::Token expected, string* err);
State* state_;
BindingEnv* env_; BindingEnv* env_;
FileReader* file_reader_;
Lexer lexer_;
ManifestParserOptions options_; ManifestParserOptions options_;
bool quiet_; bool quiet_;
}; };

51
src/parser.cc Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "parser.h"
#include "disk_interface.h"
#include "metrics.h"
bool Parser::Load(const string& filename, string* err, Lexer* parent) {
METRIC_RECORD(".ninja parse");
string contents;
string read_err;
if (file_reader_->ReadFile(filename, &contents, &read_err) !=
FileReader::Okay) {
*err = "loading '" + filename + "': " + read_err;
if (parent)
parent->Error(string(*err), err);
return false;
}
// The lexer needs a nul byte at the end of its input, to know when it's done.
// It takes a StringPiece, and StringPiece's string constructor uses
// string::data(). data()'s return value isn't guaranteed to be
// null-terminated (although in practice - libc++, libstdc++, msvc's stl --
// it is, and C++11 demands that too), so add an explicit nul byte.
contents.resize(contents.size() + 1);
return Parse(filename, contents, err);
}
bool Parser::ExpectToken(Lexer::Token expected, string* err) {
Lexer::Token token = lexer_.ReadToken();
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;
}

50
src/parser.h Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NINJA_PARSER_H_
#define NINJA_PARSER_H_
#include <string>
using namespace std;
#include "lexer.h"
struct FileReader;
struct State;
/// Base class for parsers.
struct Parser {
Parser(State* state, FileReader* file_reader)
: state_(state), file_reader_(file_reader) {}
/// Load and parse a file.
bool Load(const string& filename, string* err, Lexer* parent = NULL);
protected:
/// If the next token is not \a expected, produce an error string
/// saying "expected foo, got bar".
bool ExpectToken(Lexer::Token expected, string* err);
State* state_;
FileReader* file_reader_;
Lexer lexer_;
private:
/// Parse a file, given its contents as a string.
virtual bool Parse(const string& filename, const string& input,
string* err) = 0;
};
#endif // NINJA_PARSER_H_