mirror of
https://github.com/verilator/verilator.git
synced 2025-04-05 12:12:39 +00:00
Split and re-order AstNode definitions (#3622)
- Move DType representations into V3AstNodeDType.h - Move AstNodeMath and subclasses into V3AstNodeMath.h - Move any other AstNode subtypes into V3AstNodeOther.h - Fix up out-of-order definitions via inline methods and implementations in V3Inlines.h and V3AstNodes.cpp - Enforce declaration order of AstNode subtypes via astgen, which will now fail when definitions are mis-ordered.
This commit is contained in:
parent
e43c089ab8
commit
22b9dfb9c9
@ -1153,8 +1153,9 @@ Generally what would you do to add a new feature?
|
|||||||
language and has a lot of back-and-forth with Verilator's grammar. Copy
|
language and has a lot of back-and-forth with Verilator's grammar. Copy
|
||||||
the appropriate rules to src/verilog.y and modify the productions.
|
the appropriate rules to src/verilog.y and modify the productions.
|
||||||
|
|
||||||
4. If a new Ast type is needed, add it to V3AstNodes.h. Follow the
|
4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h.
|
||||||
convention described above about the AstNode type hierarchy.
|
Follow the convention described above about the AstNode type hierarchy.
|
||||||
|
Ordering of definitions is enforced by ``astgen``.
|
||||||
|
|
||||||
5. Now you can run "test_regress/t/t_<newtestcase>.pl --debug" and it'll
|
5. Now you can run "test_regress/t/t_<newtestcase>.pl --debug" and it'll
|
||||||
probably fail but you'll see a
|
probably fail but you'll see a
|
||||||
|
@ -276,9 +276,16 @@ VLCOV_OBJS = \
|
|||||||
|
|
||||||
NON_STANDALONE_HEADERS = \
|
NON_STANDALONE_HEADERS = \
|
||||||
V3AstInlines.h \
|
V3AstInlines.h \
|
||||||
V3AstNodes.h \
|
V3AstNodeDType.h \
|
||||||
|
V3AstNodeMath.h \
|
||||||
|
V3AstNodeOther.h \
|
||||||
V3WidthCommit.h \
|
V3WidthCommit.h \
|
||||||
|
|
||||||
|
AST_DEFS := \
|
||||||
|
V3AstNodeDType.h \
|
||||||
|
V3AstNodeMath.h \
|
||||||
|
V3AstNodeOther.h \
|
||||||
|
|
||||||
#### Linking
|
#### Linking
|
||||||
|
|
||||||
ifeq ($(VL_VLCOV),)
|
ifeq ($(VL_VLCOV),)
|
||||||
@ -301,8 +308,8 @@ V3Number_test: V3Number_test.o
|
|||||||
|
|
||||||
#### Modules
|
#### Modules
|
||||||
|
|
||||||
%__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h
|
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS)
|
||||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp
|
$(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) $*.cpp
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||||
@ -332,8 +339,8 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h
|
|||||||
$(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir)
|
$(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir)
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
|
V3Ast__gen_classes.h : $(ASTGEN) $(AST_DEFS)
|
||||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) --classes
|
$(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) --classes
|
||||||
|
|
||||||
V3ParseBison.h: V3ParseBison.c
|
V3ParseBison.h: V3ParseBison.c
|
||||||
|
|
||||||
|
1119
src/V3Ast.h
1119
src/V3Ast.h
File diff suppressed because it is too large
Load Diff
@ -17,9 +17,9 @@
|
|||||||
#ifndef VERILATOR_V3ASTINLINES_H_
|
#ifndef VERILATOR_V3ASTINLINES_H_
|
||||||
#define VERILATOR_V3ASTINLINES_H_
|
#define VERILATOR_V3ASTINLINES_H_
|
||||||
|
|
||||||
#ifndef VERILATOR_V3ASTNODES_H_
|
#ifndef VERILATOR_V3AST_H_
|
||||||
#error "Use V3Ast.h as the include"
|
#error "Use V3Ast.h as the include"
|
||||||
#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h
|
#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h and relaed
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@ -91,4 +91,124 @@ inline void AstIfaceRefDType::cloneRelink() {
|
|||||||
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep();
|
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstRange::AstRange(FileLine* fl, int left, int right)
|
||||||
|
: ASTGEN_SUPER_Range(fl) {
|
||||||
|
setOp2p(new AstConst{fl, static_cast<uint32_t>(left)});
|
||||||
|
setOp3p(new AstConst{fl, static_cast<uint32_t>(right)});
|
||||||
|
}
|
||||||
|
AstRange::AstRange(FileLine* fl, const VNumRange& range)
|
||||||
|
: ASTGEN_SUPER_Range(fl) {
|
||||||
|
setOp2p(new AstConst{fl, static_cast<uint32_t>(range.left())});
|
||||||
|
setOp3p(new AstConst{fl, static_cast<uint32_t>(range.right())});
|
||||||
|
}
|
||||||
|
int AstRange::leftConst() const {
|
||||||
|
AstConst* const constp = VN_CAST(leftp(), Const);
|
||||||
|
return (constp ? constp->toSInt() : 0);
|
||||||
|
}
|
||||||
|
int AstRange::rightConst() const {
|
||||||
|
AstConst* const constp = VN_CAST(rightp(), Const);
|
||||||
|
return (constp ? constp->toSInt() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AstQueueDType::boundConst() const {
|
||||||
|
AstConst* const constp = VN_CAST(boundp(), Const);
|
||||||
|
return (constp ? constp->toSInt() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstPin::AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp)
|
||||||
|
: ASTGEN_SUPER_Pin(fl)
|
||||||
|
, m_pinNum{pinNum}
|
||||||
|
, m_name{varname->name()} {
|
||||||
|
setNOp1p(exprp);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstDpiExportUpdated::AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep)
|
||||||
|
: ASTGEN_SUPER_DpiExportUpdated(fl) {
|
||||||
|
addOp1p(new AstVarRef{fl, varScopep, VAccess::WRITE});
|
||||||
|
}
|
||||||
|
|
||||||
|
AstVarScope* AstDpiExportUpdated::varScopep() const { return VN_AS(op1p(), VarRef)->varScopep(); }
|
||||||
|
|
||||||
|
AstPackArrayDType::AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp,
|
||||||
|
AstRange* rangep)
|
||||||
|
: ASTGEN_SUPER_PackArrayDType(fl) {
|
||||||
|
childDTypep(dtp); // Only for parser
|
||||||
|
refDTypep(nullptr);
|
||||||
|
setOp2p(rangep);
|
||||||
|
dtypep(nullptr); // V3Width will resolve
|
||||||
|
const int width = subDTypep()->width() * rangep->elementsConst();
|
||||||
|
widthForce(width, width);
|
||||||
|
}
|
||||||
|
AstPackArrayDType::AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
|
||||||
|
: ASTGEN_SUPER_PackArrayDType(fl) {
|
||||||
|
refDTypep(dtp);
|
||||||
|
setOp2p(rangep);
|
||||||
|
dtypep(this);
|
||||||
|
const int width = subDTypep()->width() * rangep->elementsConst();
|
||||||
|
widthForce(width, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AstBasicDType::hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); }
|
||||||
|
int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); }
|
||||||
|
int AstBasicDType::elements() const {
|
||||||
|
return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements());
|
||||||
|
}
|
||||||
|
bool AstBasicDType::littleEndian() const {
|
||||||
|
return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AstActive::hasInitial() const { return m_sensesp->hasInitial(); }
|
||||||
|
bool AstActive::hasSettle() const { return m_sensesp->hasSettle(); }
|
||||||
|
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
|
||||||
|
|
||||||
|
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp)
|
||||||
|
: ASTGEN_SUPER_ElabDisplay(fl) {
|
||||||
|
setOp1p(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp});
|
||||||
|
m_displayType = dispType;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstCStmt::AstCStmt(FileLine* fl, const string& textStmt)
|
||||||
|
: ASTGEN_SUPER_CStmt(fl) {
|
||||||
|
addNOp1p(new AstText{fl, textStmt, true});
|
||||||
|
}
|
||||||
|
|
||||||
|
AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut)
|
||||||
|
: ASTGEN_SUPER_CMath(fl)
|
||||||
|
, m_cleanOut{cleanOut}
|
||||||
|
, m_pure{true} {
|
||||||
|
addNOp1p(new AstText{fl, textStmt, true});
|
||||||
|
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
|
||||||
|
: ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {}
|
||||||
|
// This form only allowed post-link (see above)
|
||||||
|
AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
|
||||||
|
: ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) {
|
||||||
|
varScopep(varscp);
|
||||||
|
}
|
||||||
|
bool AstVarRef::same(const AstVarRef* samep) const {
|
||||||
|
if (varScopep()) {
|
||||||
|
return (varScopep() == samep->varScopep() && access() == samep->access());
|
||||||
|
} else {
|
||||||
|
return (selfPointer() == samep->selfPointer() && varp()->name() == samep->varp()->name()
|
||||||
|
&& access() == samep->access());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
|
||||||
|
if (varScopep()) {
|
||||||
|
return (varScopep() == samep->varScopep());
|
||||||
|
} else {
|
||||||
|
return (selfPointer() == samep->selfPointer()
|
||||||
|
&& (!selfPointer().empty() || !samep->selfPointer().empty())
|
||||||
|
&& varp()->name() == samep->varp()->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
|
||||||
|
: ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access)
|
||||||
|
, m_dotted{dotted} {
|
||||||
|
dtypeFrom(varp);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
1341
src/V3AstNodeDType.h
Normal file
1341
src/V3AstNodeDType.h
Normal file
File diff suppressed because it is too large
Load Diff
4426
src/V3AstNodeMath.h
Normal file
4426
src/V3AstNodeMath.h
Normal file
File diff suppressed because it is too large
Load Diff
4363
src/V3AstNodeOther.h
Normal file
4363
src/V3AstNodeOther.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -155,6 +155,51 @@ void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Numb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
|
||||||
|
AstRange* rangep) {
|
||||||
|
// wantwidth=0 means figure it out, but if a widthmin is >=0
|
||||||
|
// we allow width 0 so that {{0{x}},y} works properly
|
||||||
|
// wantwidthmin=-1: default, use wantwidth if it is non zero
|
||||||
|
m.m_keyword = kwd;
|
||||||
|
// Implicitness: // "parameter X" is implicit and sized from initial
|
||||||
|
// value, "parameter reg x" not
|
||||||
|
if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) {
|
||||||
|
if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC;
|
||||||
|
}
|
||||||
|
if (numer == VSigning::NOSIGN) {
|
||||||
|
if (keyword().isSigned()) {
|
||||||
|
numer = VSigning::SIGNED;
|
||||||
|
} else if (keyword().isUnsigned()) {
|
||||||
|
numer = VSigning::UNSIGNED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numeric(numer);
|
||||||
|
if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width
|
||||||
|
if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false);
|
||||||
|
const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth;
|
||||||
|
widthForce(wantwidth, wmin);
|
||||||
|
} else if (!rangep) { // Set based on keyword properties
|
||||||
|
// V3Width will pull from this width
|
||||||
|
if (keyword().width() > 1 && !isOpaque()) {
|
||||||
|
m.m_nrange.init(keyword().width() - 1, 0, false);
|
||||||
|
}
|
||||||
|
widthForce(keyword().width(), keyword().width());
|
||||||
|
} else {
|
||||||
|
widthForce(rangep->elementsConst(),
|
||||||
|
rangep->elementsConst()); // Maybe unknown if parameters underneath it
|
||||||
|
}
|
||||||
|
setNOp1p(rangep);
|
||||||
|
dtypep(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AstBasicDType::cvtRangeConst() {
|
||||||
|
if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) {
|
||||||
|
m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()};
|
||||||
|
rangep()->unlinkFrBackWithNext()->deleteTree();
|
||||||
|
rangep(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int AstBasicDType::widthAlignBytes() const {
|
int AstBasicDType::widthAlignBytes() const {
|
||||||
if (width() <= 8) {
|
if (width() <= 8) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -1026,6 +1071,11 @@ AstConstPool::AstConstPool(FileLine* fl)
|
|||||||
addOp1p(m_modp);
|
addOp1p(m_modp);
|
||||||
m_modp->addStmtp(m_scopep);
|
m_modp->addStmtp(m_scopep);
|
||||||
}
|
}
|
||||||
|
const char* AstConstPool::broken() const {
|
||||||
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
||||||
|
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
|
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
|
||||||
FileLine* const fl = initp->fileline();
|
FileLine* const fl = initp->fileline();
|
||||||
@ -1297,11 +1347,19 @@ void AstCell::dump(std::ostream& str) const {
|
|||||||
str << " ->UNLINKED:" << modName();
|
str << " ->UNLINKED:" << modName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstCell::broken() const {
|
||||||
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
void AstCellInline::dump(std::ostream& str) const {
|
void AstCellInline::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " -> " << origModName();
|
str << " -> " << origModName();
|
||||||
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
||||||
}
|
}
|
||||||
|
const char* AstCellInline::broken() const {
|
||||||
|
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
const char* AstClassPackage::broken() const {
|
const char* AstClassPackage::broken() const {
|
||||||
BROKEN_BASE_RTN(AstNodeModule::broken());
|
BROKEN_BASE_RTN(AstNodeModule::broken());
|
||||||
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
||||||
@ -1346,6 +1404,17 @@ void AstClass::dump(std::ostream& str) const {
|
|||||||
if (isExtended()) str << " [EXT]";
|
if (isExtended()) str << " [EXT]";
|
||||||
if (isVirtual()) str << " [VIRT]";
|
if (isVirtual()) str << " [VIRT]";
|
||||||
}
|
}
|
||||||
|
const char* AstClass::broken() const {
|
||||||
|
BROKEN_BASE_RTN(AstNodeModule::broken());
|
||||||
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstClass::cloneRelink() {
|
||||||
|
AstNodeModule::cloneRelink();
|
||||||
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
||||||
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||||
|
}
|
||||||
|
}
|
||||||
AstClass* AstClassExtends::classp() const {
|
AstClass* AstClassExtends::classp() const {
|
||||||
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
||||||
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
||||||
@ -1368,6 +1437,18 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
|||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "class:" << name();
|
str << "class:" << name();
|
||||||
}
|
}
|
||||||
|
const char* AstClassRefDType::broken() const {
|
||||||
|
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
||||||
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstClassRefDType::cloneRelink() {
|
||||||
|
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
|
||||||
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
||||||
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string AstClassRefDType::name() const { return classp() ? classp()->name() : "<unlinked>"; }
|
||||||
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
if (immediate()) str << " [IMMEDIATE]";
|
if (immediate()) str << " [IMMEDIATE]";
|
||||||
@ -1385,6 +1466,11 @@ void AstEnumItemRef::dump(std::ostream& str) const {
|
|||||||
str << "UNLINKED";
|
str << "UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstEnumItemRef::broken() const {
|
||||||
|
BROKEN_RTN(m_itemp && !m_itemp->brokeExists());
|
||||||
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
void AstIfaceRefDType::dump(std::ostream& str) const {
|
void AstIfaceRefDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (cellName() != "") str << " cell=" << cellName();
|
if (cellName() != "") str << " cell=" << cellName();
|
||||||
@ -1416,6 +1502,46 @@ void AstInitArray::dump(std::ostream& str) const {
|
|||||||
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstInitArray::broken() const {
|
||||||
|
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||||
|
BROKEN_RTN(!it->second);
|
||||||
|
BROKEN_RTN(!it->second->brokeExists());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstInitArray::cloneRelink() {
|
||||||
|
for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||||
|
if (it->second->clonep()) it->second = it->second->clonep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstNode* AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) {
|
||||||
|
// Returns old value, caller must garbage collect
|
||||||
|
AstNode* oldp = nullptr;
|
||||||
|
const auto it = m_map.find(index);
|
||||||
|
if (it != m_map.end()) {
|
||||||
|
oldp = it->second->valuep();
|
||||||
|
it->second->valuep(newp);
|
||||||
|
} else {
|
||||||
|
AstInitItem* const itemp = new AstInitItem(fileline(), newp);
|
||||||
|
m_map.emplace(index, itemp);
|
||||||
|
addOp2p(itemp);
|
||||||
|
}
|
||||||
|
return oldp;
|
||||||
|
}
|
||||||
|
AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
|
||||||
|
const auto it = m_map.find(index);
|
||||||
|
if (it == m_map.end()) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return it->second->valuep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
|
||||||
|
AstNode* valuep = getIndexValuep(index);
|
||||||
|
if (!valuep) valuep = defaultp();
|
||||||
|
return valuep;
|
||||||
|
}
|
||||||
|
|
||||||
void AstJumpGo::dump(std::ostream& str) const {
|
void AstJumpGo::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
@ -1425,6 +1551,13 @@ void AstJumpGo::dump(std::ostream& str) const {
|
|||||||
str << "%Error:UNLINKED";
|
str << "%Error:UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstJumpGo::broken() const {
|
||||||
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstJumpGo::cloneRelink() {
|
||||||
|
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
|
||||||
|
}
|
||||||
void AstJumpLabel::dump(std::ostream& str) const {
|
void AstJumpLabel::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
@ -1447,6 +1580,13 @@ void AstMemberSel::dump(std::ostream& str) const {
|
|||||||
str << "%Error:UNLINKED";
|
str << "%Error:UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void AstMemberSel::cloneRelink() {
|
||||||
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
||||||
|
}
|
||||||
|
const char* AstMemberSel::broken() const {
|
||||||
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
void AstMethodCall::dump(std::ostream& str) const {
|
void AstMethodCall::dump(std::ostream& str) const {
|
||||||
this->AstNodeFTaskRef::dump(str);
|
this->AstNodeFTaskRef::dump(str);
|
||||||
if (isStatement()) str << " [STMT]";
|
if (isStatement()) str << " [STMT]";
|
||||||
@ -1468,6 +1608,13 @@ void AstModportFTaskRef::dump(std::ostream& str) const {
|
|||||||
str << " -> UNLINKED";
|
str << " -> UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstModportFTaskRef::broken() const {
|
||||||
|
BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstModportFTaskRef::cloneRelink() {
|
||||||
|
if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep();
|
||||||
|
}
|
||||||
void AstModportVarRef::dump(std::ostream& str) const {
|
void AstModportVarRef::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (direction().isAny()) str << " " << direction();
|
if (direction().isAny()) str << " " << direction();
|
||||||
@ -1478,6 +1625,13 @@ void AstModportVarRef::dump(std::ostream& str) const {
|
|||||||
str << " -> UNLINKED";
|
str << " -> UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstModportVarRef::broken() const {
|
||||||
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstModportVarRef::cloneRelink() {
|
||||||
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
||||||
|
}
|
||||||
void AstPin::dump(std::ostream& str) const {
|
void AstPin::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (modVarp()) {
|
if (modVarp()) {
|
||||||
@ -1488,6 +1642,17 @@ void AstPin::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
if (svImplicit()) str << " [.SV]";
|
if (svImplicit()) str << " [.SV]";
|
||||||
}
|
}
|
||||||
|
const char* AstPin::broken() const {
|
||||||
|
BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists());
|
||||||
|
BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
string AstPin::prettyOperatorName() const {
|
||||||
|
return modVarp()
|
||||||
|
? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "")
|
||||||
|
+ "port connection " + modVarp()->prettyNameQ())
|
||||||
|
: "port connection";
|
||||||
|
}
|
||||||
void AstPrintTimeScale::dump(std::ostream& str) const {
|
void AstPrintTimeScale::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
str << " " << timeunit();
|
str << " " << timeunit();
|
||||||
@ -1533,6 +1698,23 @@ void AstRefDType::dump(std::ostream& str) const {
|
|||||||
str << " -> UNLINKED";
|
str << " -> UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstRefDType::broken() const {
|
||||||
|
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
|
||||||
|
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
|
||||||
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstRefDType::cloneRelink() {
|
||||||
|
if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep();
|
||||||
|
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||||
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
||||||
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstNodeDType* AstRefDType::subDTypep() const {
|
||||||
|
if (typedefp()) return typedefp()->subDTypep();
|
||||||
|
return refDTypep(); // Maybe nullptr
|
||||||
|
}
|
||||||
void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
||||||
this->AstNodeDType::dump(str);
|
this->AstNodeDType::dump(str);
|
||||||
if (packed()) str << " [PACKED]";
|
if (packed()) str << " [PACKED]";
|
||||||
@ -1603,6 +1785,32 @@ void AstNetlist::dump(std::ostream& str) const {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
||||||
}
|
}
|
||||||
|
const char* AstNetlist::broken() const {
|
||||||
|
BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists());
|
||||||
|
BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists());
|
||||||
|
BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists());
|
||||||
|
BROKEN_RTN(m_evalp && !m_evalp->brokeExists());
|
||||||
|
BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
|
||||||
|
BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
AstPackage* AstNetlist::dollarUnitPkgAddp() {
|
||||||
|
if (!m_dollarUnitPkgp) {
|
||||||
|
m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName());
|
||||||
|
// packages are always libraries; don't want to make them a "top"
|
||||||
|
m_dollarUnitPkgp->inLibrary(true);
|
||||||
|
m_dollarUnitPkgp->modTrace(false); // may reconsider later
|
||||||
|
m_dollarUnitPkgp->internal(true);
|
||||||
|
addModulep(m_dollarUnitPkgp);
|
||||||
|
}
|
||||||
|
return m_dollarUnitPkgp;
|
||||||
|
}
|
||||||
|
void AstNetlist::createTopScope(AstScope* scopep) {
|
||||||
|
UASSERT(scopep, "Must not be nullptr");
|
||||||
|
UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits");
|
||||||
|
m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep};
|
||||||
|
scopep->modp()->addStmtp(v3Global.rootp()->topScopep());
|
||||||
|
}
|
||||||
void AstNodeModule::dump(std::ostream& str) const {
|
void AstNodeModule::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " L" << level();
|
str << " L" << level();
|
||||||
@ -1620,10 +1828,24 @@ void AstPackageExport::dump(std::ostream& str) const {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " -> " << packagep();
|
str << " -> " << packagep();
|
||||||
}
|
}
|
||||||
|
const char* AstPackageExport ::broken() const {
|
||||||
|
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstPackageExport::cloneRelink() {
|
||||||
|
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
|
||||||
|
}
|
||||||
void AstPackageImport::dump(std::ostream& str) const {
|
void AstPackageImport::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " -> " << packagep();
|
str << " -> " << packagep();
|
||||||
}
|
}
|
||||||
|
const char* AstPackageImport::broken() const {
|
||||||
|
BROKEN_RTN(!m_packagep || !m_packagep->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstPackageImport::cloneRelink() {
|
||||||
|
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
|
||||||
|
}
|
||||||
void AstPatMember::dump(std::ostream& str) const {
|
void AstPatMember::dump(std::ostream& str) const {
|
||||||
this->AstNodeMath::dump(str);
|
this->AstNodeMath::dump(str);
|
||||||
if (isDefault()) str << " [DEFAULT]";
|
if (isDefault()) str << " [DEFAULT]";
|
||||||
@ -1691,10 +1913,30 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
|
|||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "[*]";
|
str << "[*]";
|
||||||
}
|
}
|
||||||
|
bool AstWildcardArrayDType::same(const AstNode* samep) const {
|
||||||
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||||
|
if (!asamep->subDTypep()) return false;
|
||||||
|
return (subDTypep() == asamep->subDTypep());
|
||||||
|
}
|
||||||
|
bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const {
|
||||||
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||||
|
return type() == samep->type() && asamep->subDTypep()
|
||||||
|
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||||
|
}
|
||||||
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "[]";
|
str << "[]";
|
||||||
}
|
}
|
||||||
|
bool AstUnsizedArrayDType::same(const AstNode* samep) const {
|
||||||
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||||
|
if (!asamep->subDTypep()) return false;
|
||||||
|
return (subDTypep() == asamep->subDTypep());
|
||||||
|
}
|
||||||
|
bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const {
|
||||||
|
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||||
|
return type() == samep->type() && asamep->subDTypep()
|
||||||
|
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||||
|
}
|
||||||
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
|
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "emptyq";
|
str << "emptyq";
|
||||||
@ -1742,6 +1984,9 @@ void AstVarRef::dump(std::ostream& str) const {
|
|||||||
str << "UNLINKED";
|
str << "UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool AstVarRef::same(const AstNode* samep) const {
|
||||||
|
return same(static_cast<const AstVarRef*>(samep));
|
||||||
|
}
|
||||||
void AstVar::dump(std::ostream& str) const {
|
void AstVar::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (isSc()) str << " [SC]";
|
if (isSc()) str << " [SC]";
|
||||||
@ -1804,6 +2049,13 @@ void AstClassOrPackageRef::dump(std::ostream& str) const {
|
|||||||
str << "UNLINKED";
|
str << "UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AstNodeModule* AstClassOrPackageRef::classOrPackagep() const {
|
||||||
|
AstNode* foundp = m_classOrPackageNodep;
|
||||||
|
while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
||||||
|
if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp();
|
||||||
|
return VN_CAST(foundp, NodeModule);
|
||||||
|
}
|
||||||
|
|
||||||
void AstDot::dump(std::ostream& str) const {
|
void AstDot::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (colon()) str << " [::]";
|
if (colon()) str << " [::]";
|
||||||
@ -1817,6 +2069,16 @@ void AstActive::dump(std::ostream& str) const {
|
|||||||
str << "UNLINKED";
|
str << "UNLINKED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const char* AstActive::broken() const {
|
||||||
|
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstActive::cloneRelink() {
|
||||||
|
if (m_sensesp->clonep()) {
|
||||||
|
m_sensesp = m_sensesp->clonep();
|
||||||
|
UASSERT(m_sensesp, "Bad clone cross link: " << this);
|
||||||
|
}
|
||||||
|
}
|
||||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||||
@ -1920,6 +2182,14 @@ void AstCFunc::dump(std::ostream& str) const {
|
|||||||
if (isDestructor()) str << " [DTOR]";
|
if (isDestructor()) str << " [DTOR]";
|
||||||
if (isVirtual()) str << " [VIRT]";
|
if (isVirtual()) str << " [VIRT]";
|
||||||
}
|
}
|
||||||
|
const char* AstCFunc::broken() const {
|
||||||
|
BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void AstCFunc::cloneRelink() {
|
||||||
|
if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep();
|
||||||
|
}
|
||||||
|
|
||||||
void AstCUse::dump(std::ostream& str) const {
|
void AstCUse::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str << " [" << useType() << "]";
|
str << " [" << useType() << "]";
|
||||||
|
9592
src/V3AstNodes.h
9592
src/V3AstNodes.h
File diff suppressed because it is too large
Load Diff
92
src/astgen
92
src/astgen
@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import glob
|
import glob
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
# from pprint import pprint, pformat
|
# from pprint import pprint, pformat
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, name, superClass):
|
def __init__(self, name, superClass, file, lineno):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._superClass = superClass
|
self._superClass = superClass
|
||||||
self._subClasses = [] # Initially list, but tuple after completion
|
self._subClasses = [] # Initially list, but tuple after completion
|
||||||
@ -19,6 +20,9 @@ class Node:
|
|||||||
self._typeId = None # Concrete type identifier number for leaf classes
|
self._typeId = None # Concrete type identifier number for leaf classes
|
||||||
self._typeIdMin = None # Lowest type identifier number for class
|
self._typeIdMin = None # Lowest type identifier number for class
|
||||||
self._typeIdMax = None # Highest type identifier number for class
|
self._typeIdMax = None # Highest type identifier number for class
|
||||||
|
self._file = file # File this class is defined in
|
||||||
|
self._lineno = lineno # Line this class is defined on
|
||||||
|
self._ordIdx = None # Ordering index of this class
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -32,6 +36,14 @@ class Node:
|
|||||||
def isCompleted(self):
|
def isCompleted(self):
|
||||||
return isinstance(self._subClasses, tuple)
|
return isinstance(self._subClasses, tuple)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file(self):
|
||||||
|
return self._file
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lineno(self):
|
||||||
|
return self._lineno
|
||||||
|
|
||||||
# Pre completion methods
|
# Pre completion methods
|
||||||
def addSubClass(self, subClass):
|
def addSubClass(self, subClass):
|
||||||
assert not self.isCompleted
|
assert not self.isCompleted
|
||||||
@ -39,20 +51,25 @@ class Node:
|
|||||||
|
|
||||||
# Computes derived properties over entire class hierarchy.
|
# Computes derived properties over entire class hierarchy.
|
||||||
# No more changes to the hierarchy are allowed once this was called
|
# No more changes to the hierarchy are allowed once this was called
|
||||||
def complete(self, typeId=0):
|
def complete(self, typeId=0, ordIdx=0):
|
||||||
assert not self.isCompleted
|
assert not self.isCompleted
|
||||||
# Sort sub-classes and convert to tuple, which marks completion
|
# Sort sub-classes and convert to tuple, which marks completion
|
||||||
self._subClasses = tuple(sorted(self._subClasses,
|
self._subClasses = tuple(
|
||||||
key=lambda _: _.name))
|
sorted(self._subClasses,
|
||||||
|
key=lambda _: (bool(_._subClasses), _.name)))
|
||||||
|
|
||||||
|
self._ordIdx = ordIdx
|
||||||
|
ordIdx = ordIdx + 1
|
||||||
|
|
||||||
# Leaves
|
# Leaves
|
||||||
if self.isLeaf:
|
if self.isLeaf:
|
||||||
self._typeId = typeId
|
self._typeId = typeId
|
||||||
return typeId + 1
|
return typeId + 1, ordIdx
|
||||||
|
|
||||||
# Non-leaves
|
# Non-leaves
|
||||||
for subClass in self._subClasses:
|
for subClass in self._subClasses:
|
||||||
typeId = subClass.complete(typeId)
|
typeId, ordIdx = subClass.complete(typeId, ordIdx)
|
||||||
return typeId
|
return typeId, ordIdx
|
||||||
|
|
||||||
# Post completion methods
|
# Post completion methods
|
||||||
@property
|
@property
|
||||||
@ -117,6 +134,11 @@ class Node:
|
|||||||
self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses)
|
self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses)
|
||||||
return self._typeIdMax
|
return self._typeIdMax
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ordIdx(self):
|
||||||
|
assert self.isCompleted
|
||||||
|
return self._ordIdx
|
||||||
|
|
||||||
def isSubClassOf(self, other):
|
def isSubClassOf(self, other):
|
||||||
assert self.isCompleted
|
assert self.isCompleted
|
||||||
if self is other:
|
if self is other:
|
||||||
@ -472,7 +494,7 @@ class Cpt:
|
|||||||
|
|
||||||
def read_types(filename):
|
def read_types(filename):
|
||||||
with open(filename) as fh:
|
with open(filename) as fh:
|
||||||
for line in fh:
|
for (lineno, line) in enumerate(fh, start=1):
|
||||||
line = re.sub(r'//.*$', '', line)
|
line = re.sub(r'//.*$', '', line)
|
||||||
if re.match(r'^\s*$', line):
|
if re.match(r'^\s*$', line):
|
||||||
continue
|
continue
|
||||||
@ -485,12 +507,12 @@ def read_types(filename):
|
|||||||
if re.search(r'Ast', supern) or classn == "AstNode":
|
if re.search(r'Ast', supern) or classn == "AstNode":
|
||||||
classn = re.sub(r'^Ast', '', classn)
|
classn = re.sub(r'^Ast', '', classn)
|
||||||
supern = re.sub(r'^Ast', '', supern)
|
supern = re.sub(r'^Ast', '', supern)
|
||||||
if supern:
|
if not supern:
|
||||||
superClass = Nodes[supern]
|
sys.exit("%Error: 'Ast{}' has no super-class".format(
|
||||||
node = Node(classn, superClass)
|
classn))
|
||||||
Nodes[supern].addSubClass(node)
|
superClass = Nodes[supern]
|
||||||
else:
|
node = Node(classn, superClass, filename, lineno)
|
||||||
node = Node(classn, None)
|
superClass.addSubClass(node)
|
||||||
Nodes[classn] = node
|
Nodes[classn] = node
|
||||||
|
|
||||||
|
|
||||||
@ -701,6 +723,9 @@ Version 2.0.
|
|||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('-I', action='store', help='source code include directory')
|
parser.add_argument('-I', action='store', help='source code include directory')
|
||||||
|
parser.add_argument('--astdef',
|
||||||
|
action='append',
|
||||||
|
help='add AST definition file (relative to -I)')
|
||||||
parser.add_argument('--classes',
|
parser.add_argument('--classes',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='makes class declaration files')
|
help='makes class declaration files')
|
||||||
@ -710,8 +735,13 @@ parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames')
|
|||||||
|
|
||||||
Args = parser.parse_args()
|
Args = parser.parse_args()
|
||||||
|
|
||||||
read_types(Args.I + "/V3Ast.h")
|
# Set up the root AstNode type. It is standalone so we don't need to parse the
|
||||||
read_types(Args.I + "/V3AstNodes.h")
|
# sources for this.
|
||||||
|
Nodes["Node"] = Node("Node", None, "AstNode", 1)
|
||||||
|
|
||||||
|
# Read Ast node definitions
|
||||||
|
for filename in Args.astdef:
|
||||||
|
read_types(os.path.join(Args.I, filename))
|
||||||
|
|
||||||
# Compute derived properties over the whole AstNode hierarchy
|
# Compute derived properties over the whole AstNode hierarchy
|
||||||
Nodes["Node"].complete()
|
Nodes["Node"].complete()
|
||||||
@ -731,6 +761,36 @@ for node in SortedNodes:
|
|||||||
"%Error: Non-final AstNode subclasses must be named AstNode*: Ast"
|
"%Error: Non-final AstNode subclasses must be named AstNode*: Ast"
|
||||||
+ node.name)
|
+ node.name)
|
||||||
|
|
||||||
|
# Check ordering of node definitions
|
||||||
|
files = tuple(sorted(set(_.file for _ in SortedNodes)))
|
||||||
|
|
||||||
|
hasOrderingError = False
|
||||||
|
for file in files:
|
||||||
|
nodes = tuple(filter(lambda _, f=file: _.file == f, SortedNodes))
|
||||||
|
expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx)))
|
||||||
|
actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno))
|
||||||
|
expect = {
|
||||||
|
node: pred
|
||||||
|
for pred, node in zip((None, ) + expectOrder[:-1], expectOrder)
|
||||||
|
}
|
||||||
|
actual = {
|
||||||
|
node: pred
|
||||||
|
for pred, node in zip((None, ) + actualOrder[:-1], actualOrder)
|
||||||
|
}
|
||||||
|
for node in nodes:
|
||||||
|
if expect[node] != actual[node]:
|
||||||
|
hasOrderingError = True
|
||||||
|
pred = expect[node]
|
||||||
|
print(file + ":" + str(node.lineno) +
|
||||||
|
": %Error: Definition of 'Ast" + node.name +
|
||||||
|
"' is out of order. Should be " +
|
||||||
|
("right after 'Ast" + pred.name +
|
||||||
|
"'" if pred else "first in file") + ".",
|
||||||
|
file=sys.stderr)
|
||||||
|
|
||||||
|
if hasOrderingError:
|
||||||
|
sys.exit("%Error: Stopping due to out of order definitions listed above")
|
||||||
|
|
||||||
read_stages(Args.I + "/Verilator.cpp")
|
read_stages(Args.I + "/Verilator.cpp")
|
||||||
|
|
||||||
source_files = glob.glob(Args.I + "/*.y")
|
source_files = glob.glob(Args.I + "/*.y")
|
||||||
|
@ -117,7 +117,7 @@ def _suppress(filename, linenum, eid):
|
|||||||
if filename == "*":
|
if filename == "*":
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Cleanup for e.g. ../V3AstNodes.h
|
# Cleanup for e.g. ../V3AstNode*.h
|
||||||
filename = re.sub(r'^\.\./(.*)', r'src/\1', filename)
|
filename = re.sub(r'^\.\./(.*)', r'src/\1', filename)
|
||||||
|
|
||||||
# Specific suppressions
|
# Specific suppressions
|
||||||
|
Loading…
Reference in New Issue
Block a user