Skip to content

Commit

Permalink
Introduce type ids
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Dec 3, 2023
1 parent 6805d45 commit 622818a
Show file tree
Hide file tree
Showing 30 changed files with 219 additions and 201 deletions.
13 changes: 12 additions & 1 deletion docs/docs/language/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,15 @@ public type A struct {

### Available attributes
- `core.compiler.alwaysEmitVTable: bool`: Always emit a vtable for the annotated struct
- `core.compiler.packed: bool`: Pack the annotated struct
- `core.compiler.packed: bool`: Pack the annotated struct

## Interface attributes
```spice
#[core.compiler.fixedTypeId = 230]
public type A interface {
// ...
}
```

### Available attributes
- `core.compiler.fixedTypeId: int`: Set a fixed type id for the annotated interface. Intended for internal use only.
21 changes: 12 additions & 9 deletions media/specs/better-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ this symbol gets removed and

**Example:** <br>
Source file A imports source file B as `sourceB`. B contains a struct with the name `TestStruct`. Formerly, you would
have written `sourceB::TestStruct` to access the struct from source file A. Now you only need to write `TestStruct`.
have written `sourceB::TestStruct` to access the struct from source file A. Now you only need to write `TestStruct` and the
compile resolves the correct struct automatically.

Registry of A:

| Name | Pointer to SymbolTableEntry | Pointer to scope of symbol | Import entry | Predecessor name |
|---------------------|-----------------------------|----------------------------|---------------------|----------------------|
| sourceB::TestStruct | Pointer to struct entry | Ptr to struct body scope | Ptr to import entry | |
| TestStruct | Pointer to struct entry | Ptr to struct body scope | Ptr to import entry | sourceB::TestStruct |
| Name | TypeId | Pointer to SymbolTableEntry | Pointer to scope of symbol | Import entry |
|---------------------|--------|-----------------------------|----------------------------|---------------------|
| sourceB::TestStruct | 256 | Pointer to struct entry | Ptr to struct body scope | Ptr to import entry |
| TestStruct | 256 | Pointer to struct entry | Ptr to struct body scope | Ptr to import entry |

However, if A also imports source file C, which also exposes a struct with the name `TestStruct`, there would be an
ambiguity between `sourceB::TestStruct` and `sourceC::TestStruct` when you just write `TestStruct`. Therefore, when
Expand All @@ -33,7 +34,9 @@ Accessing `TestStruct` without a scope identifier, leads to a compile error.

Registry of A:

| Name | Pointer to SymbolTableEntry | Pointer to scope of symbol | Import entry | Predecessor name |
|---------------------|-----------------------------|------------------------------|---------------------|------------------|
| sourceB::TestStruct | Pointer to struct entry | Pointer to struct body scope | Ptr to import entry | |
| sourceC::TestStruct | Pointer to struct entry | Pointer to struct body scope | Ptr to import entry | |
| Name | TypeId | Pointer to SymbolTableEntry | Pointer to scope of symbol | Import entry |
|---------------------|--------|-----------------------------|------------------------------|---------------------|
| sourceB::TestStruct | 256 | Pointer to struct entry | Pointer to struct body scope | Ptr to import entry |
| sourceC::TestStruct | 257 | Pointer to struct entry | Pointer to struct body scope | Ptr to import entry |

This behaviour is intended to avoid bugs due to accessing the wrong structs by accident.
27 changes: 9 additions & 18 deletions src/SourceFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,30 +588,21 @@ SourceFile *SourceFile::requestRuntimeModule(RuntimeModule runtimeModule) {

bool SourceFile::isRuntimeModuleAvailable(RuntimeModule runtimeModule) const { return importedRuntimeModules & runtimeModule; }

void SourceFile::addNameRegistryEntry(const std::string &symbolName, SymbolTableEntry *entry, Scope *scope,
bool keepNewOnCollision /*=true*/, SymbolTableEntry *importEntry /*=nullptr*/,
const std::string &predecessorName /*=""*/) {
void SourceFile::addNameRegistryEntry(const std::string &symbolName, uint64_t typeId, SymbolTableEntry *entry, Scope *scope,
bool keepNewOnCollision, SymbolTableEntry *importEntry) {
if (keepNewOnCollision || !exportedNameRegistry.contains(symbolName)) // Overwrite potential existing entry
exportedNameRegistry[symbolName] = {symbolName, entry, scope, importEntry, predecessorName};
exportedNameRegistry[symbolName] = {symbolName, typeId, entry, scope, importEntry};
else // Name collision => we must remove the existing entry
exportedNameRegistry.erase(symbolName);
}

const NameRegistryEntry *SourceFile::getNameRegistryEntry(std::string symbolName) const {
const NameRegistryEntry *SourceFile::getNameRegistryEntry(const std::string &symbolName) const {
if (!exportedNameRegistry.contains(symbolName))
return nullptr;

// Resolve the 'fullest-qualified' registry entry for the given name
const NameRegistryEntry *registryEntry;
do {
assert(exportedNameRegistry.contains(symbolName));
registryEntry = &exportedNameRegistry.at(symbolName);
if (registryEntry->importEntry)
registryEntry->importEntry->used = true;
symbolName = registryEntry->predecessorName;
} while (!symbolName.empty());

return registryEntry;
// Resolve registry entry for the given name
assert(exportedNameRegistry.contains(symbolName));
return &exportedNameRegistry.at(symbolName);
}

void SourceFile::checkForSoftErrors() {
Expand Down Expand Up @@ -669,10 +660,10 @@ void SourceFile::mergeNameRegistries(const SourceFile &importedSourceFile, const
std::string newName = importName;
newName += SCOPE_ACCESS_TOKEN;
newName += originalName;
exportedNameRegistry.insert({newName, {newName, entry.targetEntry, entry.targetScope, importEntry}});
exportedNameRegistry.insert({newName, {newName, entry.typeId, entry.targetEntry, entry.targetScope, importEntry}});
// Add the shortened name, considering the name collision
const bool keepOnCollision = importedSourceFile.alwaysKeepSymbolsOnNameCollision;
addNameRegistryEntry(originalName, entry.targetEntry, entry.targetScope, keepOnCollision, importEntry, newName);
addNameRegistryEntry(originalName, entry.typeId, entry.targetEntry, entry.targetScope, keepOnCollision, importEntry);
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@ struct CompilerOutput {

struct NameRegistryEntry {
std::string name;
uint64_t typeId; // Set for structs, interfaces and enums
SymbolTableEntry *targetEntry;
Scope *targetScope;
SymbolTableEntry *importEntry = nullptr;
std::string predecessorName;
};

class SourceFile {
public:
// Constructors
explicit SourceFile(GlobalResourceManager &resourceManager, SourceFile *parent, std::string name,
const std::filesystem::path &filePath, bool stdFile);
SourceFile(GlobalResourceManager &resourceManager, SourceFile *parent, std::string name, const std::filesystem::path &filePath,
bool stdFile);
SourceFile(const SourceFile &) = delete;

// Friend classes
Expand Down Expand Up @@ -138,9 +138,9 @@ class SourceFile {
[[nodiscard]] bool isAlreadyImported(const std::string &filePathSearch) const;
SourceFile *requestRuntimeModule(RuntimeModule runtimeModule);
bool isRuntimeModuleAvailable(RuntimeModule runtimeModule) const;
void addNameRegistryEntry(const std::string &symbolName, SymbolTableEntry *entry, Scope *scope, bool keepNewOnCollision = true,
SymbolTableEntry *importEntry = nullptr, const std::string &predecessorName = "");
[[nodiscard]] const NameRegistryEntry *getNameRegistryEntry(std::string symbolName) const;
void addNameRegistryEntry(const std::string &symbolName, uint64_t typeId, SymbolTableEntry *entry, Scope *scope,
bool keepNewOnCollision = true, SymbolTableEntry *importEntry = nullptr);
[[nodiscard]] const NameRegistryEntry *getNameRegistryEntry(const std::string &symbolName) const;
void checkForSoftErrors();
void collectAndPrintWarnings();
bool isStringRT() const;
Expand Down
2 changes: 1 addition & 1 deletion src/Spice.g4
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ functionDef: topLevelDefAttr? specifierLst? F LESS dataType GREATER fctName (LES
procedureDef: topLevelDefAttr? specifierLst? P fctName (LESS typeLst GREATER)? LPAREN paramLst? RPAREN LBRACE stmtLst RBRACE;
fctName: (TYPE_IDENTIFIER DOT)? IDENTIFIER | OPERATOR overloadableOp;
structDef: topLevelDefAttr? specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GREATER)? STRUCT (COLON typeLst)? LBRACE field* RBRACE;
interfaceDef: specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GREATER)? INTERFACE LBRACE signature+ RBRACE;
interfaceDef: topLevelDefAttr? specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GREATER)? INTERFACE LBRACE signature+ RBRACE;
enumDef: specifierLst? TYPE TYPE_IDENTIFIER ENUM LBRACE enumItemLst RBRACE;
genericTypeDef: TYPE TYPE_IDENTIFIER typeAltsLst SEMICOLON;
aliasDef: specifierLst? TYPE TYPE_IDENTIFIER ALIAS dataType SEMICOLON;
Expand Down
18 changes: 18 additions & 0 deletions src/ast/ASTBuilder.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2021-2023 ChilliBits. All rights reserved.

#include "ASTBuilder.h"
#include "Attributes.h"

#include <regex>

Expand Down Expand Up @@ -112,6 +113,7 @@ std::any ASTBuilder::visitStructDef(SpiceParser::StructDefContext *ctx) {

// Enrich
structDefNode->structName = getIdentifier(ctx->TYPE_IDENTIFIER());
structDefNode->typeId = resourceManager.getNextCustomTypeId();
structDefNode->hasTemplateTypes = ctx->LESS();
structDefNode->hasInterfaces = ctx->COLON();

Expand All @@ -123,6 +125,10 @@ std::any ASTBuilder::visitStructDef(SpiceParser::StructDefContext *ctx) {
for (AttrNode *attr : structDefNode->attrs()->attrLst()->attributes())
attr->target = AttrNode::TARGET_STRUCT;

// Check if a custom type id was set
if (structDefNode->attrs() && structDefNode->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_FIXED_TYPE_ID))
structDefNode->typeId = structDefNode->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_FIXED_TYPE_ID)->intValue;

return concludeNode(ctx, structDefNode);
}

Expand All @@ -131,11 +137,22 @@ std::any ASTBuilder::visitInterfaceDef(SpiceParser::InterfaceDefContext *ctx) {

// Enrich
interfaceDefNode->interfaceName = getIdentifier(ctx->TYPE_IDENTIFIER());
interfaceDefNode->typeId = resourceManager.getNextCustomTypeId();
interfaceDefNode->hasTemplateTypes = ctx->LESS();

// Visit children
visitChildren(ctx);

// Tell the attributes that they are interface attributes
if (interfaceDefNode->attrs())
for (AttrNode *attr : interfaceDefNode->attrs()->attrLst()->attributes())
attr->target = AttrNode::TARGET_INTERFACE;

// Check if a custom type id was set
if (interfaceDefNode->attrs() && interfaceDefNode->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_FIXED_TYPE_ID))
interfaceDefNode->typeId =
interfaceDefNode->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_FIXED_TYPE_ID)->intValue;

return concludeNode(ctx, interfaceDefNode);
}

Expand All @@ -144,6 +161,7 @@ std::any ASTBuilder::visitEnumDef(SpiceParser::EnumDefContext *ctx) {

// Enrich
enumDefNode->enumName = getIdentifier(ctx->TYPE_IDENTIFIER());
enumDefNode->typeId = resourceManager.getNextCustomTypeId();

// Visit children
visitChildren(ctx);
Expand Down
9 changes: 7 additions & 2 deletions src/ast/ASTNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ class StructDefNode : public ASTNode {

// Public members
std::string structName;
uint64_t typeId;
bool hasTemplateTypes = false;
bool hasInterfaces = false;
bool emitVTable = false;
Expand All @@ -378,6 +379,7 @@ class InterfaceDefNode : public ASTNode {
std::any accept(ParallelizableASTVisitor *visitor) const override { return visitor->visitInterfaceDef(this); }

// Public get methods
[[nodiscard]] TopLevelDefinitionAttrNode *attrs() const { return getChild<TopLevelDefinitionAttrNode>(); }
[[nodiscard]] SpecifierLstNode *specifierLst() const { return getChild<SpecifierLstNode>(); }
[[nodiscard]] std::vector<SignatureNode *> signatures() const { return getChildren<SignatureNode>(); }
[[nodiscard]] TypeLstNode *templateTypeLst() const { return getChild<TypeLstNode>(0); }
Expand All @@ -387,6 +389,7 @@ class InterfaceDefNode : public ASTNode {

// Public members
std::string interfaceName;
uint64_t typeId;
bool hasTemplateTypes = false;
SymbolTableEntry *entry = nullptr;
TypeSpecifiers interfaceSpecifiers = TypeSpecifiers::of(TY_INTERFACE);
Expand All @@ -411,6 +414,7 @@ class EnumDefNode : public ASTNode {

// Public members
std::string enumName;
uint64_t typeId;
SymbolTableEntry *entry = nullptr;
TypeSpecifiers enumSpecifiers = TypeSpecifiers::of(TY_ENUM);
Scope *enumScope;
Expand Down Expand Up @@ -1033,8 +1037,9 @@ class AttrNode : public ASTNode {
TARGET_INVALID = 0,
TARGET_MODULE = 1 << 0,
TARGET_STRUCT = 1 << 1,
TARGET_FCT_PROC = 1 << 2,
TARGET_EXT_DECL = 1 << 3,
TARGET_INTERFACE = 1 << 2,
TARGET_FCT_PROC = 1 << 3,
TARGET_EXT_DECL = 1 << 4,
};

enum AttrType : uint8_t {
Expand Down
8 changes: 8 additions & 0 deletions src/ast/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ static constexpr const char *const ATTR_CORE_LINKER_DLL = "core.linker.dll";
static constexpr const char *const ATTR_CORE_COMPILER_MANGLE = "core.compiler.mangle";
static constexpr const char *const ATTR_CORE_COMPILER_MANGLED_NAME = "core.compiler.mangledName";
static constexpr const char *const ATTR_CORE_COMPILER_KEEP_ON_NAME_COLLISION = "core.compiler.alwaysKeepOnNameCollision";
static constexpr const char *const ATTR_CORE_COMPILER_FIXED_TYPE_ID = "core.compiler.fixedTypeId";
static constexpr const char *const ATTR_CORE_COMPILER_EMIT_VTABLE = "core.compiler.alwaysEmitVTable";
static constexpr const char *const ATTR_CORE_COMPILER_PACKED = "core.compiler.packed";
static constexpr const char *const ATTR_CORE_COMPILER_WARNINGS_IGNORE = "core.compiler.warnings.ignore";
Expand Down Expand Up @@ -54,6 +55,13 @@ static const std::unordered_map<std::string, AttrConfigValue> ATTR_CONFIGS = {
.type = AttrNode::TYPE_BOOL,
},
},
{
ATTR_CORE_COMPILER_FIXED_TYPE_ID,
{
.target = AttrNode::TARGET_STRUCT | AttrNode::TARGET_INTERFACE,
.type = AttrNode::TYPE_INT,
},
},
{
ATTR_CORE_LINKER_DLL,
{
Expand Down
6 changes: 4 additions & 2 deletions src/global/GlobalResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,18 @@ GlobalResourceManager::~GlobalResourceManager() {
llvm::llvm_shutdown();
}

SourceFile *GlobalResourceManager::createSourceFile(SourceFile *parent, const std::string &dependencyName,
SourceFile *GlobalResourceManager::createSourceFile(SourceFile *parent, const std::string &depName,
const std::filesystem::path &path, bool isStdFile) {
// Check if the source file was already added (e.g. by another source file that imports it)
const std::string filePathStr = path.string();

// Create the new source file if it does not exist yet
if (!sourceFiles.contains(filePathStr))
sourceFiles.insert({filePathStr, std::make_unique<SourceFile>(*this, parent, dependencyName, path, isStdFile)});
sourceFiles.insert({filePathStr, std::make_unique<SourceFile>(*this, parent, depName, path, isStdFile)});

return sourceFiles.at(filePathStr).get();
}

uint64_t GlobalResourceManager::getNextCustomTypeId() { return nextCustomTypeId++; }

} // namespace spice::compiler
10 changes: 7 additions & 3 deletions src/global/GlobalResourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ class GlobalResourceManager {
public:
// Constructors
explicit GlobalResourceManager(const CliOptions &cliOptions);
GlobalResourceManager(const GlobalResourceManager &) = delete;
GlobalResourceManager(const GlobalResourceManager &) = delete; // Global resource manager can only exist exactly once
~GlobalResourceManager();

// Public methods
SourceFile *createSourceFile(SourceFile *parent, const std::string &dependencyName, const std::filesystem::path &path,
bool isStdFile);
SourceFile *createSourceFile(SourceFile *parent, const std::string &depName, const std::filesystem::path &path, bool isStdFile);
uint64_t getNextCustomTypeId();

// Public members
llvm::LLVMContext context;
Expand All @@ -58,6 +58,10 @@ class GlobalResourceManager {
BS::synced_stream tout;
std::mutex objectEmitLock;
ErrorManager errorManager;

private:
// Private members
std::atomic<uint64_t> nextCustomTypeId = UINT8_MAX + 1; // Start at 256 because all primitive types come first
};

} // namespace spice::compiler
Loading

0 comments on commit 622818a

Please sign in to comment.