Skip to content

Commit

Permalink
Fix special characters and variables.
Browse files Browse the repository at this point in the history
  • Loading branch information
dillof committed Apr 14, 2024
1 parent db41faa commit efb0596
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 24 deletions.
16 changes: 8 additions & 8 deletions src/File.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ File::File(const std::filesystem::path& filename, const std::filesystem::path& b
source_directory = filename.parent_path();
build_filename = replace_extension(build_directory / source_filename.filename(), "ninja");

bindings.add(std::make_shared<FilenameVariable>("build_directory", FilenameList{Filename{Filename::Type::BUILD, build_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("source_directory", FilenameList{Filename{Filename::Type::SOURCE, source_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("build_directory", FilenameList{Filename{Filename::Type::COMPLETE, build_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("source_directory", FilenameList{Filename{Filename::Type::COMPLETE, source_directory.string()}}));
if (is_top()) {
bindings.add(std::make_shared<FilenameVariable>("top_build_directory", FilenameList{Filename{Filename::Type::BUILD, build_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("top_source_directory", FilenameList{Filename{Filename::Type::SOURCE,source_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("top_build_directory", FilenameList{Filename{Filename::Type::COMPLETE, top_file()->build_directory.string()}}));
bindings.add(std::make_shared<FilenameVariable>("top_source_directory", FilenameList{Filename{Filename::Type::COMPLETE, top_file()->source_directory.string()}}));
}

parse(filename);
Expand All @@ -61,11 +61,11 @@ void File::process() {
if (is_top()) {
auto bindings = Bindings{};
bindings.add(std::shared_ptr<Variable>(new TextVariable{"command", Text{std::vector<Word>{
Word{"fast-ninja"},
Word{" "},
Word{source_directory}
Word{"fast-ninja", false},
Word{" ", false},
Word{source_directory, true}
}}}));
bindings.add(std::shared_ptr<Variable>(new TextVariable{"generator", Text{"1"}}));
bindings.add(std::shared_ptr<Variable>(new TextVariable{"generator", Text{"1", false}}));

rules["fast-ninja"] = Rule(this, "fast-ninja", bindings);
auto outputs = std::vector<Filename>{};
Expand Down
2 changes: 1 addition & 1 deletion src/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class File: public Scope {
void create_output() const;

const File* next_file() const;
const File* top_file() const;
const File* top_file() const {return top()->as_file();}

std::filesystem::path source_directory;
std::filesystem::path build_directory;
Expand Down
2 changes: 1 addition & 1 deletion src/Text.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Text::Text(Tokenizer& tokenizer) {
if (token.type == Tokenizer::TokenType::NEWLINE) {
break;
}
words.emplace_back(token.string());
words.emplace_back(token.string(), false);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Text.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class Variable;
class Text {
public:
Text() = default;
Text(Tokenizer& tokenizer);
explicit Text(std::string value): Text{std::vector<Word>{Word{std::move(value)}}} {}
explicit Text(Tokenizer& tokenizer);
explicit Text(std::string value, bool escape): Text{std::vector<Word>{Word{std::move(value), escape}}} {}
explicit Text(std::vector<Word> elements): words{std::move(elements)} {}

void append(const Text& other) {words.insert(words.end(), other.words.begin(), other.words.end());}
Expand Down
30 changes: 24 additions & 6 deletions src/Word.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Word::Word(Tokenizer& tokenizer) {

if (token.is_variable_refrence()) {
if (!string.empty()) {
elements.emplace_back(string);
elements.emplace_back(StringElement{string, true});
string = "";
}
elements.emplace_back(VariableReference(token.value));
Expand All @@ -57,12 +57,12 @@ Word::Word(Tokenizer& tokenizer) {
elements.emplace_back(FilenameWord(tokenizer));
}
else {
string += token.value;
string += token.string();
}
}

if (!string.empty()) {
elements.emplace_back(string);
elements.emplace_back(StringElement{string, true});
}
}

Expand All @@ -82,8 +82,8 @@ void Word::print(std::ostream& stream) const {
const FilenameWord* filename_word{};

for (auto& element: elements) {
if (std::holds_alternative<std::string>(element)) {
*current_string += std::get<std::string>(element);
if (std::holds_alternative<StringElement>(element)) {
*current_string += std::get<StringElement>(element).string();
}
else if (std::holds_alternative<VariableReference>(element)) {
auto& variable = std::get<VariableReference>(element);
Expand Down Expand Up @@ -143,7 +143,7 @@ void Word::resolve(const ResolveContext& context) {
auto& variable_reference = std::get<VariableReference>(element);
variable_reference.resolve(context);
if (variable_reference.is_text_variable()) {
element = variable_reference.variable->string();
element = StringElement{variable_reference.variable->string(), true};
}
}
else if (std::holds_alternative<FilenameWord>(element)) {
Expand All @@ -153,7 +153,25 @@ void Word::resolve(const ResolveContext& context) {
}
}


std::ostream& operator<<(std::ostream& stream, const Word& word) {
word.print(stream);
return stream;
}

std::string Word::StringElement::string() const {
if (!escape || text.find(' ') == std::string::npos) {
return text;
}

std::string escaped;
for (char c : text) {
if (c == ' ') {
escaped += "$ ";
}
else {
escaped += c;
}
}
return escaped;
}
20 changes: 14 additions & 6 deletions src/Word.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class FilenameWord;

class Word {
public:
Word(Tokenizer& tokenizer);
explicit Word(std::string text) {elements.emplace_back(std::move(text));};
explicit Word(Tokenizer& tokenizer);
explicit Word(std::string text, bool escape) {elements.emplace_back(StringElement(std::move(text), escape));};
explicit Word(VariableReference variable_reference) {elements.emplace_back(variable_reference);}
Word() = default;

Expand All @@ -58,11 +58,19 @@ class Word {
void resolve(const ResolveContext& scope);

private:
void append_string(std::string string) { elements.emplace_back(std::move(string)); }
void append_variable(std::string string) { elements.emplace_back(VariableReference(std::move(string))); }
void append_filename(FilenameWord filname) {elements.emplace_back(std::move(filname));}
class StringElement {
public:
StringElement(std::string text, bool escape): text{std::move(text)}, escape{escape} {}
StringElement() = default;

std::vector<std::variant<std::string, VariableReference, FilenameWord>> elements;
[[nodiscard]] std::string string() const;

private:
std::string text;
bool escape{false};
};

std::vector<std::variant<StringElement, VariableReference, FilenameWord>> elements;
};

std::ostream& operator<<(std::ostream& stream, const Word& word);
Expand Down
18 changes: 18 additions & 0 deletions tests/special-characters.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
arguments ..
file build.fninja <>
rule a
command = a rule build = "a$ b" |@ || | @
end-of-inline-data
file build/build.ninja {} <>
# This file is automatically created by fast-ninja from ../build.fninja
# Do not edit.

rule a
command = a rule build = "a$ b" |@ || | @

rule fast-ninja
command = fast-ninja ..
generator = 1

build build.ninja : fast-ninja ../build.fninja
end-of-inline-data
37 changes: 37 additions & 0 deletions tests/special_directories.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
arguments ..
file build.fninja <>
rule a
command = a $in

build test: a $build_directory $source_directory $top_build_directory $top_source_directory

subninja src/build.fninja
end-of-inline-data
file src/build.fninja <>
build test: a $build_directory $source_directory $top_build_directory $top_source_directory
end-of-inline-data

file build/build.ninja {} <>
# This file is automatically created by fast-ninja from ../build.fninja
# Do not edit.

rule a
command = a $in

rule fast-ninja
command = fast-ninja ..
generator = 1

build test : a . .. . ..

build build.ninja src/build.ninja : fast-ninja ../build.fninja ../src/build.fninja

subninja src/build.ninja
end-of-inline-data

file build/src/build.ninja {} <>
# This file is automatically created by fast-ninja from ../src/build.fninja
# Do not edit.

build src/test : a src ../src . ..
end-of-inline-data

0 comments on commit efb0596

Please sign in to comment.