Skip to content

Commit

Permalink
Basic working version.
Browse files Browse the repository at this point in the history
  • Loading branch information
dillof committed Dec 21, 2023
1 parent 52fbe18 commit 0b82254
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 52 deletions.
1 change: 1 addition & 0 deletions src/Bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Bindings {
void process(const File& file);
void add(const std::string& name, Variable variable) {variables[name] = std::move(variable);}

[[nodiscard]] auto empty() const {return variables.empty();}
auto begin() { return variables.begin(); }

auto end() { return variables.end(); }
Expand Down
3 changes: 3 additions & 0 deletions src/Build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Build::Build(Tokenizer& tokenizer) {
outputs = Text{ tokenizer, Tokenizer::TokenType::COLON };
for (auto& element: outputs) {
element.type = Text::ElementType::BUILD_FILE;
}
inputs = Text{tokenizer, Tokenizer::TokenType::NEWLINE};
bindings = Bindings{ tokenizer };
}
Expand Down
74 changes: 49 additions & 25 deletions src/File.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,20 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "File.h"

#include <iostream>

#include "../foundation/lib/Util.h"
#include "Exception.h"
#include "Tokenizer.h"
#include <Exception.h>
#include <iostream>

File::File(const std::filesystem::path& filename, const File* previous) : source_filename{ filename }, build_filename{ replace_extension(filename, "ninja") }, previous{ previous } {
if (previous) {
// TODO: derive build directory relavtie to previous
}
else {
build_directory = ".";
}
File::File(const std::filesystem::path& filename, const std::filesystem::path& build_directory, const File* previous) : source_filename{ filename }, previous{ previous }, build_directory{ build_directory.lexically_normal() } {
source_directory = filename.parent_path();
build_filename = replace_extension(build_directory / source_filename.filename(), "ninja");

parse(filename);

for (const auto& subninja:subninjas) {
auto name = subninja.string();

// TODO: derive build directory
subfiles.emplace_back(source_directory / name, this);
for (const auto& subninja : subninjas) {
subfiles.emplace_back(std::make_unique<File>(source_directory / subninja, build_directory / std::filesystem::path(subninja).parent_path(), this));
}
}

Expand All @@ -73,6 +66,10 @@ void File::process() {
for (auto& build : builds) {
build.process(*this);
}

for (const auto& file: subfiles) {
file->process();
}
}

const Rule* File::find_rule(const std::string& name) const {
Expand Down Expand Up @@ -100,22 +97,47 @@ const Variable* File::find_variable(const std::string& name) const {
}

void File::create_output() const {
auto stream = std::ofstream(build_filename);
{
std::filesystem::create_directories(build_directory);
auto stream = std::ofstream(build_filename);

if (stream.fail()) {
throw Exception("can't create output '%s'", build_filename.c_str());
}
if (stream.fail()) {
throw Exception("can't create output '%s'", build_filename.c_str());
}

// TODO: print header (automatically created)
auto top_file = this;
while (top_file->previous) {
top_file = top_file->previous;
}

bindings.print(stream, "");
stream << "top_source_directory = " << top_file->source_directory.string() << std::endl;
stream << "source_directory = " << source_directory.string() << std::endl;
stream << "top_build_directory = " << top_file->build_directory.string() << std::endl;
stream << "build_directory = " << build_directory.string() << std::endl;

for (auto& pair : rules) {
pair.second.print(stream);
if (!bindings.empty()) {
stream << std::endl;
bindings.print(stream, "");
}

for (auto& pair : rules) {
pair.second.print(stream);
}

for (auto& build : builds) {
build.print(stream);
}

if (!subninjas.empty()) {
stream << std::endl;
for (auto& subninja: subninjas) {
stream << "subninja " << replace_extension(subninja, "ninja") << std::endl;
}
}
}

for (auto& build: builds) {
build.print(stream);
for (auto& subfile : subfiles) {
subfile->create_output();
}
}

Expand Down Expand Up @@ -213,5 +235,7 @@ void File::parse_rule(Tokenizer& tokenizer) {
}

void File::parse_subninja(Tokenizer& tokenizer) {
subninjas.emplace_back(tokenizer, Tokenizer::TokenType::NEWLINE);
auto text = Text{tokenizer, Tokenizer::TokenType::NEWLINE};

subninjas.emplace_back(text.string());
}
16 changes: 8 additions & 8 deletions src/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Tokenizer;
class File {
public:
File() = default;
explicit File(const std::filesystem::path& filename, const File* previous = nullptr);
explicit File(const std::filesystem::path& filename, const std::filesystem::path& build_directory = ".", const File* previous = nullptr);

void process();
[[nodiscard]] bool is_output(const std::string& word) const {return outputs.contains(word);}
Expand All @@ -57,6 +57,9 @@ class File {

void create_output() const;

std::filesystem::path source_directory;
std::filesystem::path build_directory;

private:
void parse(const std::filesystem::path& filename);
void parse_assignment(Tokenizer& tokenizer, const std::string& variable_name);
Expand All @@ -66,21 +69,18 @@ class File {
void parse_rule(Tokenizer& tokenizer);
void parse_subninja(Tokenizer& tokenizer);

std::string source_filename;
std::string build_filename;
std::filesystem::path source_filename;
std::filesystem::path build_filename;

const File* previous = nullptr;

std::filesystem::path source_directory;
std::filesystem::path build_directory;

std::unordered_set<std::string> defaults;
std::unordered_set<std::string> outputs;
std::unordered_map<std::string, Rule> rules;
std::vector<Build> builds;
Bindings bindings;
std::vector<Text> subninjas;
std::vector<File> subfiles;
std::vector<std::filesystem::path> subninjas;
std::vector<std::unique_ptr<File>> subfiles;
};

#endif // FILE_H
65 changes: 56 additions & 9 deletions src/Text.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,40 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "File.h"
#include <Exception.h>

std::string Text::Element::string() const {
if (!is_word() && !is_file()) {
return value;
}
else {
auto result = std::string{};
auto index = size_t{0};

while (index < value.size()) {
const auto special = value.find_first_of("$ \n", index);
if (special != std::string::npos) {
result += value.substr(index, special - index);
result += "$";
result += value[special];
index = special + 1;
}
else {
result += value.substr(index);
break;
}
}

if (is_build_file()) {
return "$build_directory/" + result;
}
else if (is_source_file()) {
return "$source_directory/" + result;
}
else {
return result;
}
}
}

Text::Text(Tokenizer& tokenizer, Tokenizer::TokenType terminator) {
tokenizer.skip_space();
while (const auto token = tokenizer.next()) {
Expand All @@ -44,7 +78,7 @@ Text::Text(Tokenizer& tokenizer, Tokenizer::TokenType terminator) {
throw Exception("missing ':'");
}
else if (terminator == Tokenizer::TokenType::END_SCOPE) {
emplace_back(" ", false);
emplace_back(ElementType::WHITESPACE, " ");
}
else {
return;
Expand All @@ -55,7 +89,7 @@ Text::Text(Tokenizer& tokenizer, Tokenizer::TokenType terminator) {
return;

case Tokenizer::TokenType::VARIABLE_REFERENCE:
emplace_back(token.value, true);
emplace_back(ElementType::VARIABLE, token.value);
break;

case Tokenizer::TokenType::COLON:
Expand All @@ -64,7 +98,7 @@ Text::Text(Tokenizer& tokenizer, Tokenizer::TokenType terminator) {
}
// fallthrough
default:
emplace_back(token.string(), false);
emplace_back((token.is_whitespace() ? ElementType::WHITESPACE : ElementType::WORD), token.string());
break;
}
}
Expand All @@ -77,7 +111,7 @@ std::ostream& operator<<(std::ostream& stream, const Text& text) {

void Text::print(std::ostream& stream) const {
for (const auto& element : *this) {
if (element.is_variable) {
if (element.is_variable()) {
if (element.variable) {
element.variable->print_use(stream);
}
Expand All @@ -86,22 +120,30 @@ void Text::print(std::ostream& stream) const {
}
}
else {
stream << element.value;
stream << element.string();
}
}
}

void Text::process(const File& file) {
for (auto& element : *this) {
if (element.is_variable) {
if (element.is_variable()) {
element.variable = file.find_variable(element.value);
}
else if (element.is_word()) {
if (file.is_output(element.value)) {
element.type = ElementType::BUILD_FILE;
}
else if (std::filesystem::exists(file.source_directory / element.value)) {
element.type = ElementType::SOURCE_FILE;
}
}
}
}

void Text::collect_words(std::unordered_set<std::string>& words) const {
for (auto& element : *this) {
if (element.is_variable) {
if (element.is_variable()) {
if (element.variable && element.variable->is_list) {
element.variable->value.collect_words(words);
}
Expand All @@ -113,6 +155,11 @@ void Text::collect_words(std::unordered_set<std::string>& words) const {
}

std::string Text::string() const {
// TODO: implement
return {};
auto result = std::string{};

for (auto& element: *this) {
result += element.string();
}

return result;
}
22 changes: 18 additions & 4 deletions src/Text.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,33 @@ class Variable;
*/
class Text {
public:
enum class ElementType {
BUILD_FILE,
SOURCE_FILE,
VARIABLE,
WHITESPACE,
WORD
};
class Element {
public:
Element(std::string value, bool is_variable) : value{ std::move(value) }, is_variable{ is_variable } {}
Element(ElementType type, std::string value) : type{type}, value{ std::move(value) } {}

[[nodiscard]] bool is_build_file() const {return type == ElementType::BUILD_FILE;}
[[nodiscard]] bool is_file() const {return is_build_file() || is_source_file();}
[[nodiscard]] bool is_source_file() const {return type == ElementType::SOURCE_FILE;}
[[nodiscard]] bool is_variable() const {return type == ElementType::VARIABLE;}
[[nodiscard]] bool is_word() const {return type == ElementType::WORD;}
[[nodiscard]] std::string string() const;

ElementType type;
std::string value;
bool is_variable;
const Variable *variable;
const Variable *variable = nullptr;
};

Text() = default;
Text(Tokenizer& tokenizer, Tokenizer::TokenType terminator);

void emplace_back(std::string value, bool is_variable = false) { elements.emplace_back(std::move(value), is_variable); }
void emplace_back(ElementType type, std::string value) { elements.emplace_back(type, std::move(value)); }

void print(std::ostream& stream) const;
void process(const File& file);
Expand Down
6 changes: 6 additions & 0 deletions src/Tokenizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ std::unordered_map<int, Tokenizer::CharacterType> Tokenizer::special_characters
};
// clang-format on

Tokenizer::Tokenizer(const std::filesystem::path& filename): source{filename} {
if (source.fail()) {
throw Exception("can't open '%s'", filename.c_str());
}
}

std::string Tokenizer::Token::string() const {
if (type == TokenType::VARIABLE_REFERENCE) {
return "$" + value;
Expand Down
3 changes: 2 additions & 1 deletion src/Tokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class Tokenizer {
public:
explicit Tokenizer(const std::filesystem::path& filename): source{filename} {}
explicit Tokenizer(const std::filesystem::path& filename);

enum class Skip {
NONE,
Expand Down Expand Up @@ -84,6 +84,7 @@ class Tokenizer {
Token(TokenType type, std::string value) : type{type}, value{std::move(value)} {}

explicit operator bool() const {return type != TokenType::END;}
[[nodiscard]] bool is_whitespace() const {return type == TokenType::SPACE || type == TokenType::NEWLINE;}
[[nodiscard]] std::string string() const;
[[nodiscard]] std::string type_name() const {return type_name(type);}
[[nodiscard]] static std::string type_name(TokenType type);
Expand Down
10 changes: 5 additions & 5 deletions src/fast-ninja.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class fast_ninja : public Command {
private:
static std::vector<Commandline::Option> options;

File file;
std::unique_ptr<File> file;
};

std::vector<Commandline::Option> fast_ninja::options = {};
Expand All @@ -65,12 +65,12 @@ int main(int argc, char* argv[]) {
}

void fast_ninja::process() {
auto filename = arguments.arguments[0];
const auto top_source_directory = std::filesystem::path(arguments.arguments[0]);

file = File(filename);
file.process();
file = std::make_unique<File>(top_source_directory / "build.fninja");
file->process();
}

void fast_ninja::create_output() {
file.create_output();
file->create_output();
}

0 comments on commit 0b82254

Please sign in to comment.