Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: Lukasz Dalek <[email protected]>
  • Loading branch information
Lukasz Dalek committed Apr 5, 2021
1 parent d46e152 commit c2ce719
Show file tree
Hide file tree
Showing 6 changed files with 446 additions and 2 deletions.
122 changes: 122 additions & 0 deletions verilog/analysis/symbol_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ static const verible::EnumNameMap<SymbolMetaType> kSymbolMetaTypeNames({
{"function", SymbolMetaType::kFunction},
{"task", SymbolMetaType::kTask},
{"struct", SymbolMetaType::kStruct},
{"enum", SymbolMetaType::kEnumType},
{"<enum constant>", SymbolMetaType::kEnumConstant},
{"interface", SymbolMetaType::kInterface},
{"<unspecified>", SymbolMetaType::kUnspecified},
{"<callable>", SymbolMetaType::kCallable},
Expand Down Expand Up @@ -159,6 +161,9 @@ static absl::Status DiagnoseMemberSymbolResolutionFailure(
context_name, "."));
}

static const SymbolTableNode* LookupSymbolUpwards(
const SymbolTableNode& context, absl::string_view symbol);

class SymbolTable::Builder : public TreeContextVisitor {
public:
Builder(const VerilogSourceFile& source, SymbolTable* symbol_table,
Expand Down Expand Up @@ -261,6 +266,12 @@ class SymbolTable::Builder : public TreeContextVisitor {
case NodeEnum::kStructType:
DescendStructType(node);
break;
case NodeEnum::kEnumType:
DescendEnumType(node);
break;
case NodeEnum::kLPValue:
HandlePossibleImplicitDeclaration(node);
break;
default:
Descend(node);
break;
Expand Down Expand Up @@ -455,6 +466,83 @@ class SymbolTable::Builder : public TreeContextVisitor {
}
}

void DescendEnumType(const SyntaxTreeNode& enum_type) {
CHECK(enum_type.MatchesTag(NodeEnum::kEnumType));
const absl::string_view anon_name =
current_scope_->Value().CreateAnonymousScope("enum");
SymbolTableNode& new_enum = DeclareScopedElementAndDescend(
enum_type, anon_name, SymbolMetaType::kEnumType);

const ReferenceComponent anon_type_ref{
.identifier = anon_name,
.ref_type = ReferenceType::kImmediate,
.required_metatype = SymbolMetaType::kEnumType,
// pre-resolve this symbol immediately
.resolved_symbol = &new_enum,
};

const CaptureDependentReference capture(this);
capture.Ref().PushReferenceComponent(anon_type_ref);

if (declaration_type_info_ != nullptr) {
declaration_type_info_->user_defined_type = capture.Ref().LastLeaf();
}

// Iterate over enumeration constants
for (const auto& itr : new_enum) {
const auto enum_constant_name = itr.first;
const auto& symbol = itr.second;
const auto& syntax_origin =
*ABSL_DIE_IF_NULL(symbol.Value().syntax_origin);

const ReferenceComponent itr_ref{
.identifier = enum_constant_name,
.ref_type = ReferenceType::kImmediate,
.required_metatype = SymbolMetaType::kEnumConstant,
// pre-resolve this symbol immediately
.resolved_symbol = &symbol,
};

// CaptureDependentReference class doesn't support
// copy constructor
const CaptureDependentReference cap(this);
cap.Ref().PushReferenceComponent(anon_type_ref);
cap.Ref().PushReferenceComponent(itr_ref);

// Create default DeclarationTypeInfo
DeclarationTypeInfo decl_type_info;
const ValueSaver<DeclarationTypeInfo*> save_type(&declaration_type_info_,
&decl_type_info);
declaration_type_info_->syntax_origin = &syntax_origin;
declaration_type_info_->user_defined_type = cap.Ref().LastLeaf();

// Constants should be visible in current scope so we create
// variable instances with references to enum constants
EmplaceTypedElementInCurrentScope(syntax_origin, enum_constant_name,
SymbolMetaType::kTypeAlias);
}
}

void HandlePossibleImplicitDeclaration(const SyntaxTreeNode& node) {
VLOG(2) << __FUNCTION__;

// Only left-hand side of continuous assignment statements are allowed to
// implicitly declare nets (LRM 6.10: Implicit declarations).
if (Context().DirectParentsAre(
{NodeEnum::kNetVariableAssignment, NodeEnum::kAssignmentList,
NodeEnum::kContinuousAssignmentStatement})) {
CHECK(node.MatchesTag(NodeEnum::kLPValue));

DeclarationTypeInfo decl_type_info;
const ValueSaver<DeclarationTypeInfo*> save_type(&declaration_type_info_,
&decl_type_info);
declaration_type_info_->implicit = true;
Descend(node);
} else {
Descend(node);
}
}

void HandleIdentifier(const SyntaxTreeLeaf& leaf) {
const absl::string_view text = leaf.get().text();
VLOG(2) << __FUNCTION__ << ": " << text;
Expand Down Expand Up @@ -546,6 +634,13 @@ class SymbolTable::Builder : public TreeContextVisitor {
return;
}

if (Context().DirectParentsAre(
{NodeEnum::kEnumName, NodeEnum::kEnumNameList})) {
EmplaceTypedElementInCurrentScope(leaf, text,
SymbolMetaType::kEnumConstant);
return;
}

// In DeclareInstance(), we already planted a self-reference that is
// resolved to the instance being declared.
if (Context().DirectParentIs(NodeEnum::kGateInstance)) return;
Expand Down Expand Up @@ -582,6 +677,29 @@ class SymbolTable::Builder : public TreeContextVisitor {
return;
}

// Handle possible implicit declarations here
if (declaration_type_info_ != nullptr && declaration_type_info_->implicit) {
const SymbolTableNode* resolved =
LookupSymbolUpwards(*ABSL_DIE_IF_NULL(current_scope_), text);
if (resolved == nullptr) {
// No explicit declaration found, declare here
SymbolTableNode& implicit_declaration =
EmplaceTypedElementInCurrentScope(
leaf, text, SymbolMetaType::kDataNetVariableInstance);

const ReferenceComponent implicit_ref{
.identifier = text,
.ref_type = InferReferenceType(),
.required_metatype = InferMetaType(),
// pre-resolve
.resolved_symbol = &implicit_declaration,
};

ref.PushReferenceComponent(implicit_ref);
return;
}
}

// For all other cases, grow the reference chain deeper.
// For type references, which may contained named parameters,
// when encountering the first unqualified reference, establish its
Expand Down Expand Up @@ -1697,6 +1815,10 @@ std::ostream& operator<<(std::ostream& stream,
stream << "(primitive)";
}

if (decl_type_info.implicit) {
stream << ", implicit";
}

return stream << " }";
}

Expand Down
7 changes: 7 additions & 0 deletions verilog/analysis/symbol_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ enum class SymbolMetaType {
kFunction,
kTask,
kStruct,
kEnumType,
kEnumConstant,
kInterface,

// The following enums represent classes/groups of the above types,
Expand Down Expand Up @@ -248,6 +250,11 @@ struct DeclarationTypeInfo {
// advance, and only ever moving ReferenceComponents, never copying them.
const ReferenceComponentNode* user_defined_type = nullptr;

// Indicates that this is implicit declaration.
// FIXME(ldk): Check if this could be replaced by user_defined_type pointing
// to default implicit type.
bool implicit = false;

public:
DeclarationTypeInfo() = default;

Expand Down
Loading

0 comments on commit c2ce719

Please sign in to comment.