Skip to content

Commit

Permalink
[Sema] NameAndTypeResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
LFsWang committed Dec 21, 2021
1 parent fcbb73d commit 1ef0c06
Show file tree
Hide file tree
Showing 17 changed files with 848 additions and 11 deletions.
9 changes: 5 additions & 4 deletions include/soll/ADT/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
namespace soll {

template <typename T, typename... Args>
std::vector<std::unique_ptr<T>> make_unique_vector(Args &&...args) {
std::vector<std::unique_ptr<T>> make_unique_vector(Args &&... As) {
std::vector<std::unique_ptr<T>> result;
result.reserve(sizeof...(args));
(result.emplace_back(std::forward<Args>(args)), ...);
result.reserve(sizeof...(As));
(result.emplace_back(std::forward<Args>(As)), ...);
return result;
}

Expand All @@ -29,8 +29,9 @@ template <class Type> struct cond_const<false, Type> { typedef Type type; };
/// Concatenate the contents of a container onto a vector
template <class T, class U>
std::vector<T> &operator+=(std::vector<T> &A, U &B) {
for (auto const &I : B)
for (auto const &I : B) {
A.push_back(T(I));
}
return A;
}
/// Concatenate the contents of a container onto a vector, move variant.
Expand Down
1 change: 1 addition & 0 deletions include/soll/AST/ASTBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class ASTNode {
public:
enum class ASTNodeType { DECL, STMT };
ASTNode() = default;
virtual ~ASTNode() = default;
virtual ASTNodeType getASTType() = 0;
};

Expand Down
27 changes: 25 additions & 2 deletions include/soll/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Decl : public ASTNode {
std::string Name;
Visibility Vis;
std::string UniqueName;
const ASTNode *Parent;

protected:
friend class ASTReader;
Expand All @@ -35,10 +36,11 @@ class Decl : public ASTNode {
Decl(SourceRange L,
llvm::StringRef Name = llvm::StringRef::withNullAsEmpty(nullptr),
Visibility Vis = Visibility::Default)
: Location(L), Name(Name.str()), Vis(Vis), UniqueName(Name.str()) {}
: Location(L), Name(Name.str()), Vis(Vis), UniqueName(Name.str()),
Parent(nullptr) {}

Decl(SourceRange L, std::string Name, Visibility Vis = Visibility::Default)
: Location(L), Name(Name), Vis(Vis), UniqueName(Name) {}
: Location(L), Name(Name), Vis(Vis), UniqueName(Name), Parent(nullptr) {}

public:
virtual void accept(DeclVisitor &visitor) = 0;
Expand All @@ -48,6 +50,15 @@ class Decl : public ASTNode {
llvm::StringRef getUniqueName() const { return UniqueName; }
void setUniqueName(llvm::StringRef NewName) { UniqueName = NewName.str(); }
Visibility getVisibility() const { return Vis; }

void setScope(const ASTNode *D) { Parent = D; }
/// @returns the scope this declaration resides in. Can be nullptr if it is
/// the global scope. Available only after name and type resolution step.
const ASTNode *scope() const { return Parent; }

bool isStructMember() const;

bool isVisibleAsUnqualifiedName() const;
};

/**
Expand Down Expand Up @@ -414,6 +425,18 @@ class StructDecl : public Decl {
Token getToken() const { return Tok; }
TypePtr getType() const { return Ty; }
TypePtr getConstructorType() const { return ConstructorTy; }
std::vector<Decl *> getMembers() {
std::vector<Decl *> Res;
for (auto &M : Members)
Res.push_back(M.get());
return Res;
}
std::vector<const Decl *> getMembers() const {
std::vector<const Decl *> Res;
for (auto &M : Members)
Res.push_back(M.get());
return Res;
}
};

class ModifierInvocation {
Expand Down
3 changes: 3 additions & 0 deletions include/soll/Basic/DiagnosticSemaKinds.inc
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ DIAG(err_visibility_not_match, CLASS_ERROR, (unsigned)diag::Severity::Error, "vi
DIAG(err_private_function_can_not_be_virtual, CLASS_ERROR, (unsigned)diag::Severity::Error, "private funtcion %0 can not be virtual", 0, false, 1)
DIAG(err_mutability_overriding_not_allow, CLASS_ERROR, (unsigned)diag::Severity::Error, "can not change function %0 mutability", 0, false, 1)
DIAG(err_func_to_var_overrided_unsoupport, CLASS_ERROR, (unsigned)diag::Severity::Error, "function to state variables override is unsupport", 0, false, 1)
DIAG(err_use_illegalnames, CLASS_WARNING, (unsigned)diag::Severity::Warning, "Use of illegal identifier name: '%0'", 0, false, 0)
DIAG(err_already_declared, CLASS_WARNING, (unsigned)diag::Severity::Warning, "identifier '%0' already declared", 0, false, 0)
DIAG(err_declaration_not_found, CLASS_ERROR, (unsigned)diag::Severity::Error, "identifier '%0' not found", 0, false, 0)
155 changes: 155 additions & 0 deletions include/soll/Sema/DeclarationContainer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once

#include "soll/AST/AST.h"
#include "soll/AST/Decl.h"
#include "soll/Basic/DiagnosticSema.h"
#include "soll/Sema/Sema.h"

#include <map>
#include <memory>
#include <string>
#include <vector>

namespace soll {

class DeclarationContainer {
public:
DeclarationContainer() = default;
explicit DeclarationContainer(const ASTNode *EnclosingNode,
DeclarationContainer *EnclosingContainer)
: EnclosingNode(EnclosingNode), EnclosingContainer(EnclosingContainer) {
if (EnclosingContainer)
EnclosingContainer->InnerContainers.emplace_back(this);
}

ASTNode const *enclosingNode() const { return EnclosingNode; }

void activateVariable(llvm::StringRef Name) {
assert(InvisibleDeclarations.count(Name) &&
InvisibleDeclarations.at(Name).size() == 1);
assert(Declarations.count(Name) == 0 || Declarations.at(Name).empty());

Declarations[Name].emplace_back(InvisibleDeclarations.at(Name).front());
InvisibleDeclarations.erase(Name);
}

bool isInvisible(llvm::StringRef Name) const {
return InvisibleDeclarations.count(Name);
}

bool registerDeclaration(const Decl *D, bool Invisible, bool Update) {
return registerDeclaration(D, llvm::StringRef(), nullptr, Invisible,
Update);
}

bool registerDeclaration(const Decl *D, llvm::StringRef Name,
const SourceRange *Loc, bool Invisible,
bool Update) {
if (Name.empty()) {
Name = D->getName();
}

if (Name.empty())
return true;

if (Update) {
assert(!dynamic_cast<const FunctionDecl *>(D) &&
"Attempt to update function definition.");
Declarations.erase(Name);
InvisibleDeclarations.erase(Name);
return true;
} else {
if (conflictingDeclaration(D, Name))
return false;
if (EnclosingContainer && D->isVisibleAsUnqualifiedName()) {
// TODO: isVisibleAsUnqualifiedName for struct not merged yet.
// It use old path to handle
}
}

std::vector<const Decl *> &Decls =
Invisible ? InvisibleDeclarations[Name] : Declarations[Name];
if (find(Decls.begin(), Decls.end(), D) == Decls.end())
Decls.emplace_back(D);
return true;
}

std::vector<const Decl *>
resolveName(llvm::StringRef Name, bool Recursive = false,
bool AlsoInvisible = false,
bool OnlyVisibleAsUnqualifiedNames = false) const {
std::vector<const Decl *> Res;

if (Declarations.count(Name)) {
for (auto E : Declarations.at(Name)) {
if (OnlyVisibleAsUnqualifiedNames) {
if (!E->isVisibleAsUnqualifiedName())
continue;
}
Res.emplace_back(E);
}
}

if (AlsoInvisible && InvisibleDeclarations.count(Name)) {
for (auto E : InvisibleDeclarations.at(Name)) {
if (OnlyVisibleAsUnqualifiedNames) {
if (!E->isVisibleAsUnqualifiedName())
continue;
}
Res.emplace_back(E);
}
}

if (Res.empty() && Recursive && EnclosingContainer)
Res = EnclosingContainer->resolveName(Name, true, AlsoInvisible,
OnlyVisibleAsUnqualifiedNames);

return Res;
}

const Decl *conflictingDeclaration(const Decl *D,
llvm::StringRef Name) const {
if (Name.empty())
Name = D->getName();
assert(!Name.empty());

std::vector<Decl const *> Decls;
if (Declarations.count(Name))
Decls += Declarations.at(Name);

if (InvisibleDeclarations.count(Name))
Decls += InvisibleDeclarations.at(Name);

if (dynamic_cast<const FunctionDecl *>(D) ||
dynamic_cast<const EventDecl *>(D) ||
dynamic_cast<const MagicVariableDecl *>(D)) {
for (const Decl *RegDecl : Decls) {
if (dynamic_cast<const FunctionDecl *>(D) &&
!dynamic_cast<const FunctionDecl *>(RegDecl))
return RegDecl;
if (dynamic_cast<const EventDecl *>(D) &&
!dynamic_cast<const EventDecl *>(RegDecl))
return RegDecl;
if (dynamic_cast<const MagicVariableDecl *>(D) &&
!dynamic_cast<const MagicVariableDecl *>(RegDecl))
return RegDecl;
}
} else if (Decls.size() == 1 && Decls.front() == D) {
return nullptr;
} else if (!Decls.empty()) {
return Decls.front();
}

return nullptr;
}

private:
const ASTNode *EnclosingNode = nullptr;
const DeclarationContainer *EnclosingContainer = nullptr;
std::vector<const DeclarationContainer *> InnerContainers;
std::map<llvm::StringRef, std::vector<const Decl *>> Declarations;
std::map<llvm::StringRef, std::vector<const Decl *>> InvisibleDeclarations;
};

} // namespace soll
94 changes: 94 additions & 0 deletions include/soll/Sema/GlobalContent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once

#include "soll/AST/AST.h"
#include "soll/AST/Decl.h"
#include "soll/Basic/DiagnosticSema.h"
#include "soll/Sema/Sema.h"

#include <map>
#include <memory>
#include <string>
#include <vector>

namespace soll {
/// Magic variables get negative ids for easy differentiation
namespace {
int magicVariableToID(std::string const &_name) {
if (_name == "abi")
return -1;
else if (_name == "addmod")
return -2;
else if (_name == "assert")
return -3;
else if (_name == "block")
return -4;
else if (_name == "blockhash")
return -5;
else if (_name == "ecrecover")
return -6;
else if (_name == "gasleft")
return -7;
else if (_name == "keccak256")
return -8;
else if (_name == "msg")
return -15;
else if (_name == "mulmod")
return -16;
else if (_name == "now")
return -17;
else if (_name == "require")
return -18;
else if (_name == "revert")
return -19;
else if (_name == "ripemd160")
return -20;
else if (_name == "selfdestruct")
return -21;
else if (_name == "sha256")
return -22;
else if (_name == "sha3")
return -23;
else if (_name == "suicide")
return -24;
else if (_name == "super")
return -25;
else if (_name == "tx")
return -26;
else if (_name == "type")
return -27;
else if (_name == "this")
return -28;
else
__builtin_unreachable();
}
} // namespace

class GlobalContext {
public:
void setCurrentContract(const ContractDecl *Cont) { CurrentContract = Cont; }
void resetCurrentContract() { CurrentContract = nullptr; }
const MagicVariableDecl *currentThis() {
if (!ThisCache[CurrentContract]) {
TypePtr Type = CurrentContract->getType();
ThisCache[CurrentContract] = std::make_shared<MagicVariableDecl>(
magicVariableToID("this"), "this", Type);
}
return ThisCache[CurrentContract].get();
}

const MagicVariableDecl *currentSuper() {
assert(false && "unimp currentSuper");
return nullptr;
}

GlobalContext() = default;
GlobalContext(const GlobalContext &) = delete;
~GlobalContext() = default;

private:
const ContractDecl *CurrentContract = nullptr;
std::map<const ContractDecl *, std::shared_ptr<MagicVariableDecl>> ThisCache;
std::map<const ContractDecl *, std::shared_ptr<MagicVariableDecl>> SuperCache;
};
} // namespace soll
46 changes: 46 additions & 0 deletions include/soll/Sema/NameAndTypeResolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once

#include "soll/AST/AST.h"
#include "soll/AST/Decl.h"
#include "soll/Basic/DiagnosticSema.h"
#include "soll/Sema/DeclarationContainer.h"
#include "soll/Sema/Sema.h"

#include <map>
#include <vector>

namespace soll {
class NameAndTypeResolver {
public:
void setScope(const ASTNode *Node) { CurrentScope = Scopes[Node].get(); }
bool resolveNamesAndTypesInternal(ASTNode *Node, bool ResolveCode);
bool updateDeclaration(const Decl *D) {
Scopes[nullptr]->registerDeclaration(D, false, true);
return true;
}

void activateVariable(llvm::StringRef Name) {
if (CurrentScope == nullptr) {
return;
}
if (CurrentScope->isInvisible(Name))
CurrentScope->activateVariable(Name);
}

std::vector<const Decl *> resolveName(llvm::StringRef Name,
const ASTNode *Scope) const;
std::vector<const Decl *>
nameFromCurrentScope(llvm::StringRef Name,
bool IncludeInvisibles = false) const;
NameAndTypeResolver(Sema &Action, GlobalContext &GC);
void Register(SourceUnit &SU);
bool Resolve(SourceUnit &SU);

private:
Sema &Action;
GlobalContext &GC;
std::map<const ASTNode *, std::shared_ptr<DeclarationContainer>> Scopes;
DeclarationContainer *CurrentScope = nullptr;
};
} // namespace soll

0 comments on commit 1ef0c06

Please sign in to comment.