* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "ast.h"
#include <iomanip>
#include <set>
#include <sstream>
#include "logger.h"
using namespace OHOS::Hardware;
AstObject::AstObject(const AstObject &obj) : AstObject(obj.name_, obj.type_, obj.stringValue_)
{
integerValue_ = obj.integerValue_;
src_ = obj.src_;
}
AstObject::AstObject(std::string name, uint32_t type, uint64_t value) :
type_(type),
name_(std::move(name)),
parent_(nullptr),
lineno_(0),
opCode_(0),
size_(0),
subSize_(0),
hash_(0),
integerValue_(value)
{
}
AstObject::AstObject(std::string name, uint32_t type, std::string value) : AstObject(std::move(name), type, 0)
{
stringValue_ = std::move(value);
}
AstObject::AstObject(std::string name, uint32_t type, uint64_t value, const Token &bindToken) :
AstObject(std::move(name), type, value)
{
lineno_ = bindToken.lineNo;
src_ = bindToken.src;
switch (type) {
case PARSEROP_UINT8:
case PARSEROP_UINT16:
case PARSEROP_UINT32:
case PARSEROP_UINT64:
this->type_ = FitIntegerValueType(value);
break;
default:
break;
}
}
AstObject::AstObject(std::string name, uint32_t type, std::string value, const Token &bindToken) :
AstObject(std::move(name), type, 0, bindToken)
{
stringValue_ = std::move(value);
}
AstObject::~AstObject()
{
parent_ = nullptr;
next_ = nullptr;
child_ = nullptr;
}
AstObject &AstObject::operator=(const AstObject &obj)
{
if (this != &obj) {
type_ = obj.type_;
name_ = obj.name_;
parent_ = obj.parent_;
next_ = obj.next_;
child_ = obj.child_;
lineno_ = obj.lineno_;
src_ = obj.src_;
opCode_ = obj.opCode_;
size_ = obj.size_;
subSize_ = obj.subSize_;
hash_ = obj.hash_;
integerValue_ = obj.integerValue_;
stringValue_ = obj.stringValue_;
}
return *this;
}
uint32_t AstObject::FitIntegerValueType(uint64_t value)
{
if (value <= UINT8_MAX) {
return PARSEROP_UINT8;
} else if (value <= UINT16_MAX) {
return PARSEROP_UINT16;
} else if (value <= UINT32_MAX) {
return PARSEROP_UINT32;
} else {
return PARSEROP_UINT64;
}
}
bool AstObject::AddChild(const std::shared_ptr<AstObject> &childObj)
{
if (childObj == nullptr) {
return false;
}
if (child_ == nullptr) {
child_ = childObj;
std::shared_ptr<AstObject> childNext = childObj;
while (childNext != nullptr) {
childNext->parent_ = this;
childNext = childNext->next_;
}
} else {
return child_->AddPeer(childObj);
}
return true;
}
bool AstObject::AddPeer(std::shared_ptr<AstObject> peerObject)
{
if (peerObject == nullptr) {
return false;
}
if (this == peerObject.get()) {
Logger().Error() << "add self as peer";
return false;
}
if (next_ == nullptr) {
next_ = peerObject;
} else {
std::shared_ptr<AstObject> lastNode = next_;
while (lastNode->next_ != nullptr) {
lastNode = lastNode->next_;
}
lastNode->next_ = peerObject;
}
std::shared_ptr<AstObject> peer = peerObject;
while (peer) {
peer->parent_ = parent_;
peer = peer->next_;
}
return true;
}
std::ostream &OHOS::Hardware::operator<<(std::ostream &stream, const AstObject &t)
{
if (t.type_ == PARSEROP_CONFNODE) {
auto node = static_cast<const ConfigNode *>(&t);
stream << *node;
return stream;
} else if (t.type_ == PARSEROP_CONFTERM) {
auto term = static_cast<const ConfigTerm *>(&t);
stream << *term;
return stream;
}
if (t.name_.empty()) {
stream << "|_";
} else {
stream << t.name_;
}
switch (t.type_) {
case PARSEROP_UINT8:
stream << "uint8 0x" << std::hex << t.integerValue_;
break;
case PARSEROP_UINT16:
stream << "uint16 0x" << std::hex << t.integerValue_;
break;
case PARSEROP_UINT32:
stream << "uint32 0x" << std::hex << t.integerValue_;
break;
case PARSEROP_UINT64:
stream << "uint64 0x" << std::hex << t.integerValue_;
break;
case PARSEROP_STRING:
stream << "string \"" << t.stringValue_ << "\"";
break;
case PARSEROP_ARRAY:
stream << "array";
break;
case PARSEROP_NODEREF:
stream << "noderef " << t.stringValue_;
break;
case PARSEROP_DELETE:
stream << "delete";
break;
default:
break;
}
return stream;
}
bool AstObject::Merge(std::shared_ptr<AstObject> &srcObj)
{
if (srcObj->name_ != name_) {
Logger().Error() << this->SourceInfo() << "merge different node to" << srcObj->SourceInfo();
return false;
}
if (srcObj->type_ != type_) {
Logger().Error() << this->SourceInfo() << "conflict type with " << srcObj->SourceInfo();
return false;
}
src_ = srcObj->src_;
lineno_ = srcObj->lineno_;
stringValue_ = srcObj->stringValue_;
integerValue_ = srcObj->integerValue_;
return true;
}
bool AstObject::Copy(std::shared_ptr<AstObject> src, bool overwrite)
{
if (src == nullptr) {
return false;
}
if (overwrite) {
src_ = src->src_;
lineno_ = src->lineno_;
integerValue_ = src->integerValue_;
stringValue_ = src->stringValue_;
}
return true;
}
bool AstObject::Move(std::shared_ptr<AstObject> src)
{
if (!Copy(src, true)) {
return false;
}
src->Separate();
return true;
}
std::string AstObject::SourceInfo()
{
if (src_ == nullptr) {
return "unknown";
}
std::stringstream o;
o << src_->c_str() << ":" << lineno_ << " ";
return o.str();
}
void AstObject::Remove()
{
Separate();
child_ = nullptr;
next_ = nullptr;
}
std::shared_ptr<AstObject> AstObject::Lookup(const std::string &name, uint32_t type) const
{
auto peer = child_;
while (peer != nullptr) {
if (peer->name_ == name && (type == 0 || peer->type_ == type)) {
return peer;
}
peer = peer->next_;
}
return nullptr;
}
bool AstObject::IsNumber() const
{
return type_ >= PARSEROP_UINT8 && type_ <= PARSEROP_UINT64;
}
bool AstObject::IsNode() const
{
return type_ == PARSEROP_CONFNODE;
}
bool AstObject::IsTerm() const
{
return type_ == PARSEROP_CONFTERM;
}
bool AstObject::IsArray() const
{
return type_ == PARSEROP_ARRAY;
}
void AstObject::Separate()
{
if (parent_ == nullptr) {
return;
}
if (parent_->child_.get() == this) {
parent_->child_ = next_;
next_ = nullptr;
return;
}
auto pre = parent_->child_;
while (pre != nullptr) {
if (pre->next_.get() == this) {
pre->next_ = pre->next_->next_;
break;
}
pre = pre->next_;
}
next_ = nullptr;
}
void AstObject::SetParent(AstObject *parent)
{
parent_ = parent;
}
void AstObject::SetSize(uint32_t size)
{
size_ = size;
}
void AstObject::SetSubSize(uint32_t size)
{
subSize_ = size;
}
uint32_t AstObject::GetSubSize()
{
return subSize_;
}
void AstObject::SetHash(uint32_t hash)
{
hash_ = hash;
}
uint32_t AstObject::GetSize()
{
return size_;
}
uint32_t AstObject::GetHash()
{
return hash_;
}
std::shared_ptr<AstObject> AstObject::Next()
{
return next_;
}
std::shared_ptr<AstObject> AstObject::Child()
{
return child_;
}
const std::string &AstObject::Name()
{
return name_;
}
const std::string &AstObject::StringValue()
{
return stringValue_;
}
uint64_t AstObject::IntegerValue()
{
return integerValue_;
}
uint32_t AstObject::Type()
{
return type_;
}
uint8_t AstObject::OpCode()
{
return opCode_;
}
void AstObject::SetOpCode(uint8_t opcode)
{
opCode_ = opcode;
}
bool AstObject::HasDuplicateChild()
{
return false;
}
bool AstObject::IsElders(const std::shared_ptr<AstObject> &child)
{
auto p = child.get();
while (p != nullptr) {
if (p == this) {
return true;
}
p = p->parent_;
}
return false;
}
std::shared_ptr<AstObject> AstObject::Parent()
{
return std::shared_ptr<AstObject>(parent_, [](auto p) {});
}
ConfigNode::ConfigNode(const ConfigNode &node) : ConfigNode(node.name_, node.nodeType_, node.refNodePath_)
{
auto child = node.child_;
while (child != nullptr) {
AstObject::AddChild(AstObjectFactory::Build(child));
child = child->Next();
}
}
ConfigNode::ConfigNode(std::string name, uint32_t nodeType, std::string refName) :
AstObject(std::move(name), PARSEROP_CONFNODE, ""),
refNodePath_(std::move(refName)),
nodeType_(nodeType),
inheritIndex_(0),
inheritCount_(0),
templateSignNum_(0)
{
}
ConfigNode::ConfigNode(Token &name, uint32_t nodeType, std::string refName) :
AstObject(name.strval, PARSEROP_CONFNODE, 0, name),
refNodePath_(std::move(refName)),
nodeType_(nodeType),
inheritIndex_(0),
inheritCount_(0),
templateSignNum_(0)
{
}
ConfigNode &ConfigNode::operator=(const ConfigNode &node)
{
if (this != &node) {
refNodePath_ = node.refNodePath_;
nodeType_ = node.nodeType_;
inheritIndex_ = node.inheritIndex_;
inheritCount_ = node.inheritCount_;
templateSignNum_ = node.templateSignNum_;
subClasses_ = node.subClasses_;
}
return *this;
}
const std::string &ConfigNode::NodeTypeToStr(uint32_t type)
{
static std::map<uint32_t, std::string> type2StringMap = {
{NODE_NOREF, "" },
{NODE_COPY, "NodeCopy" },
{NODE_REF, "NodeReference"},
{NODE_DELETE, "NodeDelete" },
{NODE_INHERIT, "NodeInherit" },
{NODE_TEMPLATE, "NodeTemplate" },
};
return type2StringMap[type];
}
std::ostream &OHOS::Hardware::operator<<(std::ostream &stream, const ConfigNode &t)
{
stream << "[node] " << t.name_.data() << " " << ConfigNode::NodeTypeToStr(t.nodeType_).data() << " "
<< t.refNodePath_.data();
return stream;
}
ConfigNode *ConfigNode::CastFrom(const std::shared_ptr<AstObject> &astObject)
{
return dynamic_cast<ConfigNode *>(astObject.get());
}
uint32_t ConfigNode::GetNodeType() const
{
return nodeType_;
}
const std::string &ConfigNode::GetRefPath()
{
return refNodePath_;
}
bool ConfigNode::Merge(std::shared_ptr<AstObject> &srcObj)
{
if (srcObj == nullptr) {
return true;
}
if (!srcObj->IsNode() || srcObj->Name() != name_) {
Logger().Error() << SourceInfo() << "merge conflict type with " << srcObj->SourceInfo();
return false;
}
auto srcNode = ConfigNode::CastFrom(srcObj);
if (srcNode->GetNodeType() == DELETE) {
srcObj->Separate();
this->Separate();
return true;
}
nodeType_ = srcNode->nodeType_;
refNodePath_ = srcNode->refNodePath_;
auto childSrc = srcObj->Child();
while (childSrc != nullptr) {
auto childSrcNext = childSrc->Next();
auto childDst = Lookup(childSrc->Name(), childSrc->Type());
if (childDst == nullptr) {
childSrc->Separate();
AddChild(childSrc);
} else {
if (!childDst->Merge(childSrc)) {
return false;
}
}
childSrc = childSrcNext;
}
return true;
}
void ConfigNode::SetNodeType(uint32_t nodeType)
{
nodeType_ = nodeType;
}
void ConfigNode::SetRefPath(std::string ref)
{
refNodePath_ = std::move(ref);
}
bool ConfigNode::HasDuplicateChild()
{
std::map<std::string, std::shared_ptr<AstObject>> symMap;
auto child = child_;
while (child != nullptr) {
auto sym = symMap.find(child->Name());
if (sym != symMap.end()) {
Logger().Error() << child->SourceInfo() << "redefined, first definition at " << sym->second->SourceInfo();
return true;
}
symMap[child->Name()] = child;
child = child->Next();
}
return false;
}
bool ConfigNode::InheritExpand(const std::shared_ptr<AstObject> &refObj)
{
if (refObj == nullptr) {
Logger().Error() << SourceInfo() << "inherit invalid node: " << refNodePath_;
return false;
}
if (!Copy(refObj, false)) {
return false;
}
auto templateNode = ConfigNode::CastFrom(refObj);
if (!Compare(*templateNode)) {
return false;
}
inheritIndex_ = templateNode->inheritCount_++;
templateNode->subClasses_.push_back(this);
return true;
}
bool ConfigNode::RefExpand(const std::shared_ptr<AstObject> &refObj)
{
if (nodeType_ == NODE_DELETE) {
this->Separate();
return true;
}
if (refObj->IsElders(std::shared_ptr<AstObject>(this, [](auto p) {}))) {
Logger().Error() << SourceInfo() << "circular reference " << refObj->SourceInfo();
return false;
}
bool ret = true;
if (nodeType_ == NODE_REF) {
ret = NodeRefExpand(refObj);
} else if (nodeType_ == NODE_COPY) {
ret = NodeCopyExpand(refObj);
}
return ret;
}
bool ConfigNode::Copy(std::shared_ptr<AstObject> src, bool overwrite)
{
if (!src->IsNode()) {
Logger().Error() << SourceInfo() << "node copy with different type " << src->SourceInfo();
return false;
}
auto child = src->Child();
while (child != nullptr) {
auto dst = Lookup(child->Name(), child->Type());
if (dst == nullptr) {
AddChild(AstObjectFactory::Build(child));
} else {
if (!dst->Copy(child, overwrite)) {
return false;
}
}
child = child->Next();
}
return true;
}
bool ConfigNode::Move(std::shared_ptr<AstObject> src)
{
return AstObject::Move(src);
}
bool ConfigNode::NodeRefExpand(const std::shared_ptr<AstObject> &ref)
{
if (ref == nullptr) {
Logger().Error() << SourceInfo() << "reference node '" << refNodePath_ << "' not exist";
return false;
}
return ref->Move(std::shared_ptr<AstObject>(this, [](AstObject *p) {
(void)p;
}));
}
bool ConfigNode::NodeCopyExpand(const std::shared_ptr<AstObject> &ref)
{
if (ref == nullptr) {
return false;
}
this->nodeType_ = NODE_NOREF;
return Copy(ref, false);
}
bool ConfigNode::Compare(ConfigNode &other)
{
auto objChild = child_;
while (objChild != nullptr) {
auto baseObj = Lookup(objChild->Name(), objChild->Type());
if (baseObj == nullptr) {
Logger().Error() << objChild->SourceInfo() << "not in template node: " << other.SourceInfo();
return false;
}
if (objChild->IsNode()) {
return ConfigNode::CastFrom(objChild)->Compare(*ConfigNode::CastFrom(baseObj));
}
objChild = objChild->Next();
}
return true;
}
uint32_t ConfigNode::InheritIndex()
{
return inheritIndex_;
}
uint32_t ConfigNode::InheritCount()
{
return inheritCount_;
}
uint32_t ConfigNode::TemplateSignNum()
{
return templateSignNum_;
}
void ConfigNode::SetTemplateSignNum(uint32_t sigNum)
{
templateSignNum_ = sigNum;
}
const std::list<AstObject *> &ConfigNode::SubClasses()
{
return subClasses_;
}
bool ConfigNode::IsBaseNode()
{
if (GetNodeType() != NODE_NOREF && GetNodeType() != NODE_TEMPLATE) {
return false;
}
for (auto obj = Child(); obj != nullptr; obj = obj->Next()) {
if (!obj->IsNode()) {
continue;
}
if (!CastFrom(obj)->IsBaseNode()) {
return false;
}
}
return true;
}
ConfigTerm::ConfigTerm(const ConfigTerm &term) : ConfigTerm(term.name_, nullptr)
{
AstObject::AddChild(AstObjectFactory::Build(term.child_));
src_ = term.src_;
lineno_ = term.lineno_;
}
ConfigTerm::ConfigTerm(std::string name, const std::shared_ptr<AstObject> &value) :
AstObject(std::move(name), PARSEROP_CONFTERM, 0), signNum_(0)
{
if (value != nullptr) {
child_ = value;
value->SetParent(this);
}
}
ConfigTerm::ConfigTerm(Token &name, const std::shared_ptr<AstObject> &value) :
AstObject(name.strval, PARSEROP_CONFTERM, 0, name), signNum_(0)
{
if (value != nullptr) {
child_ = value;
value->SetParent(this);
}
}
ConfigTerm &ConfigTerm::operator=(const ConfigTerm &term)
{
if (this != &term) {
refNode_ = term.refNode_;
signNum_ = term.signNum_;
}
return *this;
}
std::ostream &OHOS::Hardware::operator<<(std::ostream &stream, const ConfigTerm &t)
{
stream << "[term] " << t.name_.data();
return stream;
}
ConfigTerm *ConfigTerm::CastFrom(const std::shared_ptr<AstObject> &astObject)
{
return dynamic_cast<ConfigTerm *>(astObject.get());
}
bool ConfigTerm::Merge(std::shared_ptr<AstObject> &srcObj)
{
if (!srcObj->IsTerm()) {
Logger().Error() << SourceInfo() << "merge conflict type with " << srcObj->SourceInfo();
return false;
}
auto value = srcObj->Child();
srcObj->Child()->Separate();
child_ = nullptr;
AddChild(value);
return true;
}
bool ConfigTerm::RefExpand(const std::shared_ptr<AstObject> refObj)
{
if (child_->Type() == PARSEROP_DELETE) {
this->Separate();
return true;
}
if (child_->Type() != PARSEROP_NODEREF) {
return true;
}
if (refObj == nullptr || !refObj->IsNode() || ConfigNode::CastFrom(refObj)->GetNodeType() == NODE_REF ||
ConfigNode::CastFrom(refObj)->GetNodeType() == NODE_TEMPLATE ||
ConfigNode::CastFrom(refObj)->GetNodeType() == NODE_DELETE) {
Logger().Error() << SourceInfo() << "reference invalid node '" << child_->StringValue() << '\'';
return false;
}
refNode_ = refObj;
return true;
}
bool ConfigTerm::Copy(std::shared_ptr<AstObject> src, bool overwrite)
{
if (!overwrite) {
return true;
}
if (child_->Type() != src->Child()->Type() && (!child_->IsNumber() || !src->Child()->IsNumber())) {
Logger().Error() << src->SourceInfo() << "overwrite different type with:" << child_->SourceInfo();
return false;
}
return child_->Copy(src->Child(), overwrite);
}
bool ConfigTerm::Move(std::shared_ptr<AstObject> src)
{
return child_->Move(src->Child());
}
std::weak_ptr<AstObject> ConfigTerm::RefNode()
{
return refNode_;
}
void ConfigTerm::SetSigNum(uint32_t sigNum)
{
signNum_ = sigNum;
}
uint32_t ConfigTerm::SigNum()
{
return signNum_;
}
ConfigArray::ConfigArray() : AstObject("", PARSEROP_ARRAY, 0), arrayType_(0), arraySize_(0) {}
ConfigArray::ConfigArray(const ConfigArray &array) : ConfigArray()
{
auto child = array.child_;
while (child != nullptr) {
AstObject::AddChild(AstObjectFactory::Build(child));
child = child->Next();
}
arraySize_ = array.arraySize_;
arrayType_ = array.arrayType_;
}
ConfigArray::ConfigArray(const Token &bindToken) :
AstObject("", PARSEROP_ARRAY, 0, bindToken), arrayType_(0), arraySize_(0)
{
}
ConfigArray &ConfigArray::operator=(const ConfigArray &array)
{
if (this != &array) {
arrayType_ = array.arrayType_;
arraySize_ = array.arraySize_;
}
return *this;
}
bool ConfigArray::AddChild(const std::shared_ptr<AstObject> &childObj)
{
if (AstObject::AddChild(childObj)) {
arraySize_++;
arrayType_ = std::max(arrayType_, childObj->Type());
return true;
} else {
return false;
}
}
bool ConfigArray::Merge(std::shared_ptr<AstObject> &srcObj)
{
if (!srcObj->IsArray()) {
Logger().Error() << SourceInfo() << "merge conflict type with " << srcObj->SourceInfo();
return false;
}
auto value = srcObj->Child();
value->Separate();
child_ = value;
return true;
}
bool ConfigArray::Copy(std::shared_ptr<AstObject> src, bool overwrite)
{
if (!overwrite) {
return true;
}
auto array = ConfigArray::CastFrom(src);
child_ = nullptr;
auto t = array->child_;
while (t != nullptr) {
AddChild(AstObjectFactory::Build(t));
}
return true;
}
ConfigArray *ConfigArray::CastFrom(const std::shared_ptr<AstObject> &astObject)
{
return static_cast<ConfigArray *>(astObject.get());
}
uint16_t ConfigArray::ArraySize()
{
return arraySize_;
}
uint16_t ConfigArray::ArrayType()
{
return arrayType_;
}
std::shared_ptr<AstObject> AstObjectFactory::Build(std::shared_ptr<AstObject> object)
{
switch (object->Type()) {
case PARSEROP_CONFNODE:
return std::make_shared<ConfigNode>(*ConfigNode::CastFrom(object));
case PARSEROP_CONFTERM:
return std::make_shared<ConfigTerm>(*ConfigTerm::CastFrom(object));
case PARSEROP_ARRAY:
return std::make_shared<ConfigArray>(*ConfigArray::CastFrom(object));
default:
return std::make_shared<AstObject>(*object);
}
}
void Ast::Dump(const std::string &prefix)
{
Logger().Debug() << "Dump " << prefix << " AST:";
WalkForward([](const std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
Logger().Debug() << ::std::setw(walkDepth * 4) << " " << *current;
return NOERR;
});
}
std::shared_ptr<AstObject> Ast::GetAstRoot()
{
return astRoot_;
}
bool Ast::Merge(const std::list<std::shared_ptr<Ast>> &astList)
{
if (!RedefineCheck()) {
return false;
}
for (auto &astIt : astList) {
if (!astIt->RedefineCheck()) {
return false;
}
if (astRoot_ == nullptr) {
astRoot_ = astIt->GetAstRoot();
continue;
}
Dump("merge this");
astIt->Dump("tobe merge");
if (!astRoot_->Merge(astIt->astRoot_)) {
return false;
}
Dump("merged");
}
return true;
}
bool Ast::Expand()
{
if (astRoot_->Lookup("module", PARSEROP_CONFTERM) == nullptr) {
Logger().Error() << astRoot_->SourceInfo() << "miss 'module' attribute under root node";
return false;
}
if (!NodeExpand()) {
return false;
}
if (!InheritExpand()) {
return false;
};
redefineChecked_ = false;
if (!RedefineCheck()) {
return false;
}
Dump("expanded");
return true;
}
bool Ast::NodeExpandRef()
{
return WalkBackward([this](const std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
(void)walkDepth;
if (current->IsNode()) {
auto node = ConfigNode::CastFrom(current);
if (node->GetNodeType() != NODE_REF && node->GetNodeType() != NODE_COPY) {
return NOERR;
}
auto refObject = Lookup(current, node->GetRefPath());
if (refObject == nullptr) {
Logger().Error() << node->SourceInfo() << "reference node '" << node->GetRefPath() << "' not exist";
return EFAIL;
}
if (!refObject->IsNode()) {
Logger().Error() << node->SourceInfo() << " ref invalid node:" << node->GetRefPath();
return EFAIL;
}
auto refNode = ConfigNode::CastFrom(refObject);
if (!refNode->IsBaseNode()) {
Logger().Error() << "only allow ref base node, " << node->SourceInfo()
<< " ref invalid node which is not base type: " << node->GetRefPath();
return EFAIL;
}
if (!node->RefExpand(refObject)) {
return EFAIL;
}
}
return NOERR;
});
}
bool Ast::NodeExpandDelete()
{
return WalkBackward([this](const std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
(void)walkDepth;
if (current->IsNode()) {
auto node = ConfigNode::CastFrom(current);
if (node->GetNodeType() == NODE_DELETE) {
current->Remove();
return NOERR;
}
} else if (current->IsTerm()) {
std::shared_ptr<AstObject> ref;
if (current->child_->Type() == PARSEROP_DELETE) {
current->Remove();
return NOERR;
}
}
return NOERR;
});
}
bool Ast::NodeExpandTermRef()
{
return WalkBackward([this](const std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
(void)walkDepth;
if (current->IsTerm()) {
std::shared_ptr<AstObject> ref;
if (current->child_->Type() == PARSEROP_NODEREF) {
ref = Lookup(current, current->child_->StringValue());
if (!ConfigTerm::CastFrom(current)->RefExpand(ref)) {
return EFAIL;
}
}
}
return NOERR;
});
;
}
bool Ast::NodeExpand()
{
if (!NodeExpandRef()) {
return false;
}
if (!NodeExpandDelete()) {
return false;
}
if (!NodeExpandTermRef()) {
return false;
}
return true;
}
bool Ast::InheritExpand()
{
return WalkForward([this](const std::shared_ptr<AstObject> ¤t, int32_t) -> int32_t {
if (current->IsNode()) {
auto node = ConfigNode::CastFrom(current);
if (node->GetNodeType() != NODE_INHERIT) {
return NOERR;
}
auto inherit = Lookup(current, node->GetRefPath());
if (!node->InheritExpand(inherit)) {
return EFAIL;
}
}
return NOERR;
});
}
bool Ast::RedefineCheck()
{
if (redefineChecked_) {
return true;
}
bool ret = WalkForward([](const std::shared_ptr<AstObject> ¤t, int32_t) -> int32_t {
if (current->IsNode() && current->HasDuplicateChild()) {
return EFAIL;
}
return NOERR;
});
redefineChecked_ = true;
return ret;
}
std::shared_ptr<AstObject> Ast::Lookup(const std::shared_ptr<AstObject> &startObj, const std::string &path)
{
if (path.find('.') == std::string::npos) {
return startObj->parent_->Lookup(path);
}
auto splitPath = SplitNodePath(path, '.');
if (splitPath.front() != astRoot_->name_) {
Logger().Error() << "lookup ast with invalid path, which not begin with 'root': " << path;
return nullptr;
}
splitPath.erase(splitPath.begin());
std::shared_ptr<AstObject> target = astRoot_;
std::shared_ptr<AstObject> child = astRoot_->Child();
for (auto &it : splitPath) {
target = target->Lookup(it);
if (target == nullptr) {
return nullptr;
}
}
return target;
}
std::list<std::string> Ast::SplitNodePath(const std::string &path, char separator)
{
std::list<std::string> splitList;
std::string temp;
for (auto c : path) {
if (c != separator) {
temp.push_back(c);
} else {
if (temp.empty()) {
splitList.clear();
break;
}
splitList.push_back(temp);
temp.clear();
}
}
if (temp.empty()) {
splitList.push_back(path);
} else {
splitList.push_back(temp);
}
return splitList;
}