Skip to content

Commit

Permalink
#6031: Migrate DeclarationManager::saveDeclaration to manipulate the …
Browse files Browse the repository at this point in the history
…DefSyntaxTree instead of messing with regexes
  • Loading branch information
codereader committed Aug 13, 2022
1 parent 034e0f4 commit a7b7398
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 1 deletion.
86 changes: 85 additions & 1 deletion libs/parser/DefBlockSyntaxParser.h
Expand Up @@ -31,6 +31,15 @@ struct DefSyntaxToken
// The raw string as parsed from the source text
std::string value;

DefSyntaxToken() :
DefSyntaxToken(Type::Nothing, "")
{}

DefSyntaxToken(Type type_, const std::string& value_) :
type(type_),
value(value_)
{}

void clear()
{
type = Type::Nothing;
Expand Down Expand Up @@ -112,6 +121,8 @@ class DefWhitespaceSyntax :
private:
DefSyntaxToken _token;
public:
using Ptr = std::shared_ptr<DefWhitespaceSyntax>;

DefWhitespaceSyntax(const DefSyntaxToken& token) :
DefSyntaxNode(Type::Whitespace),
_token(token)
Expand All @@ -129,6 +140,13 @@ class DefWhitespaceSyntax :
{
return _token.value;
}

static Ptr Create(const std::string& whitespace)
{
return std::make_shared<DefWhitespaceSyntax>(
DefSyntaxToken(DefSyntaxToken::Type::Whitespace, whitespace)
);
}
};

class DefCommentSyntax :
Expand Down Expand Up @@ -174,6 +192,13 @@ class DefTypeSyntax :
{
return _token.value;
}

static Ptr Create(const std::string& typeName)
{
return std::make_shared<DefTypeSyntax>(
DefSyntaxToken(DefSyntaxToken::Type::Token, typeName)
);
}
};

class DefNameSyntax :
Expand All @@ -200,6 +225,13 @@ class DefNameSyntax :
{
return _token.value;
}

static Ptr Create(const std::string& name)
{
return std::make_shared<DefNameSyntax>(
DefSyntaxToken(DefSyntaxToken::Type::Token, name)
);
}
};

class DefBlockSyntax :
Expand All @@ -215,7 +247,7 @@ class DefBlockSyntax :
public:
using Ptr = std::shared_ptr<DefBlockSyntax>;

DefBlockSyntax(const DefSyntaxToken blockToken, std::vector<DefSyntaxNode::Ptr>&& headerNodes,
DefBlockSyntax(const DefSyntaxToken& blockToken, std::vector<DefSyntaxNode::Ptr>&& headerNodes,
int nameIndex = -1, int typeIndex = -1) :
DefSyntaxNode(Type::DeclBlock),
_blockToken(blockToken),
Expand Down Expand Up @@ -253,6 +285,12 @@ class DefBlockSyntax :
return string::trim_copy(_blockToken.value, "{}");
}

// Sets the raw block contents without the opening and closing braces
void setBlockContents(const std::string& contents)
{
_blockToken.value = "{" + contents + "}";
}

std::string getString() const override
{
std::string output;
Expand All @@ -269,6 +307,27 @@ class DefBlockSyntax :

return output;
}

static Ptr CreateTypedBlock(const std::string& type, const std::string& name)
{
std::vector<DefSyntaxNode::Ptr> headerNodes;

int typeIndex = -1;

if (!type.empty())
{
typeIndex = static_cast<int>(headerNodes.size());
headerNodes.emplace_back(DefTypeSyntax::Create(type));
headerNodes.emplace_back(DefWhitespaceSyntax::Create(" "));
}

int nameIndex = static_cast<int>(headerNodes.size());
headerNodes.emplace_back(DefNameSyntax::Create(name));
headerNodes.emplace_back(DefWhitespaceSyntax::Create(" "));

DefSyntaxToken blockToken(DefSyntaxToken::Type::BracedBlock, "{}");
return std::make_shared<DefBlockSyntax>(blockToken, std::move(headerNodes), nameIndex, typeIndex);
}
};

class DefSyntaxTree
Expand Down Expand Up @@ -300,6 +359,31 @@ class DefSyntaxTree
}
}

// Return the first block syntax node matching the given name (case-sensitive)
parser::DefBlockSyntax::Ptr findFirstNamedBlock(const std::string& name)
{
return findFirstBlock([&](const parser::DefBlockSyntax::Ptr& block)
{
return block->getName() && block->getName()->getString() == name;
});
}

// Find the first block matching the given predicate
parser::DefBlockSyntax::Ptr findFirstBlock(const std::function<bool(const parser::DefBlockSyntax::Ptr&)>& predicate)
{
parser::DefBlockSyntax::Ptr result;

foreachBlock([&](const parser::DefBlockSyntax::Ptr& block)
{
if (!result && predicate(block))
{
result = block;
}
});

return result;
}

std::string getString() const
{
return _root->getString();
Expand Down
40 changes: 40 additions & 0 deletions radiantcore/decl/DeclarationManager.cpp
Expand Up @@ -575,6 +575,45 @@ void DeclarationManager::saveDeclaration(const IDeclaration::Ptr& decl)

auto& stream = tempStream.getStream();

#if 1
parser::DefSyntaxTree::Ptr syntaxTree;

if (fs::exists(targetFile))
{
// Parse the existing file into a syntax tree for manipulation
std::ifstream inheritStream(targetFile.string());

parser::DefBlockSyntaxParser<std::istream> parser(inheritStream);

syntaxTree = parser.parse();
inheritStream.close();
}
else
{
// Since there's no existing file, create a new syntax tree
syntaxTree = std::make_shared<parser::DefSyntaxTree>();
}

// Take the first named block matching our decl. There's a risk that there is another
// decl of a different type with the same name in the tree, but we don't try to check this here
auto block = syntaxTree->findFirstNamedBlock(decl->getDeclName());

if (!block)
{
// Create a new block node with leading whitespace and add it to the tree
syntaxTree->getRoot()->appendChildNode(parser::DefWhitespaceSyntax::Create("\n\n"));

block = parser::DefBlockSyntax::CreateTypedBlock(syntax.typeName, decl->getDeclName());
syntaxTree->getRoot()->appendChildNode(block);
}

// Store the new block contents and save the file
block->setBlockContents(syntax.contents);

// Export the modified syntax tree
stream << syntaxTree->getString();

#else
// If a previous file exists, open it for reading and filter out the decl we'll be writing
if (fs::exists(targetFile))
{
Expand All @@ -601,6 +640,7 @@ void DeclarationManager::saveDeclaration(const IDeclaration::Ptr& decl)
// Write the declaration itself
writeDeclaration(stream, decl);
}
#endif

tempStream.closeAndReplaceTargetFile();

Expand Down

0 comments on commit a7b7398

Please sign in to comment.