Skip to content

Commit

Permalink
Introduce QualType
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Apr 29, 2024
1 parent ba826ef commit f5cd430
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 144 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ set(SOURCES
util/Memory.h
util/RawStringOStream.cpp
util/RawStringOStream.h
symboltablebuilder/QualType.cpp
symboltablebuilder/QualType.h
)

add_executable(spice ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})
Expand Down
8 changes: 4 additions & 4 deletions src/model/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ std::string Function::getSignature(const std::string &name, const Type &thisType
for (size_t i = 0; i < thisTemplateTypes.size(); i++) {
if (i > 0)
thisTyStr << ",";
thisTyStr << thisTemplateTypes.at(i).getName(false, ignorePublic);
thisTyStr << thisTemplateTypes.at(i).getName(false);
}
thisTyStr << ">";
}
Expand All @@ -80,15 +80,15 @@ std::string Function::getSignature(const std::string &name, const Type &thisType
// Build return type string
std::string returnTyStr;
if (!returnType.is(TY_DYN))
returnTyStr = returnType.getName(false, ignorePublic) + " ";
returnTyStr = returnType.getName(false) + " ";

// Parameter type string
std::stringstream paramTyStr;
for (size_t i = 0; i < paramList.size(); i++) {
const Param &param = paramList.at(i);
if (i > 0)
paramTyStr << ",";
paramTyStr << param.type.getName(false, ignorePublic);
paramTyStr << param.type.getName(false);
if (param.isOptional)
paramTyStr << "?";
}
Expand All @@ -100,7 +100,7 @@ std::string Function::getSignature(const std::string &name, const Type &thisType
for (size_t i = 0; i < concreteTemplateTypes.size(); i++) {
if (i > 0)
templateTyStr << ",";
templateTyStr << concreteTemplateTypes.at(i).getName(false, ignorePublic);
templateTyStr << concreteTemplateTypes.at(i).getName(false);
}
templateTyStr << ">";
}
Expand Down
10 changes: 5 additions & 5 deletions src/model/GenericType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace spice::compiler {
/**
* Checks if the given symbol type matches all conditions to get a manifestation of the current generic type
*
* @param symbolType Symbol type to be checked
* @param type Symbol type to be checked
* @param ignoreArraySize Ignore the array size for type comparison
* @param ignoreSpecifiers Ignore the type specifiers for type comparison
* @return True or false
*/
bool GenericType::checkConditionsOf(const Type &symbolType, bool ignoreArraySize /*=false*/,
bool GenericType::checkConditionsOf(const QualType &type, bool ignoreArraySize /*=false*/,
bool ignoreSpecifiers /*=false*/) const {
return checkTypeConditionOf(symbolType, ignoreArraySize, ignoreSpecifiers);
return checkTypeConditionOf(type, ignoreArraySize, ignoreSpecifiers);
}

/**
Expand All @@ -25,12 +25,12 @@ bool GenericType::checkConditionsOf(const Type &symbolType, bool ignoreArraySize
* @param ignoreSpecifiers Ignore the type specifiers for type comparison
* @return True or false
*/
bool GenericType::checkTypeConditionOf(const Type &symbolType, bool ignoreArraySize, bool ignoreSpecifiers) const {
bool GenericType::checkTypeConditionOf(const QualType &symbolType, bool ignoreArraySize, bool ignoreSpecifiers) const {
// Succeed if no type conditions are set
if (typeConditions.empty())
return true;
// Check type conditions
return std::ranges::any_of(typeConditions, [&](const Type &typeCondition) {
return std::ranges::any_of(typeConditions, [&](const QualType &typeCondition) {
return typeCondition.is(TY_DYN) || typeCondition.matches(symbolType, ignoreArraySize, ignoreSpecifiers, ignoreSpecifiers);
});
}
Expand Down
15 changes: 6 additions & 9 deletions src/model/GenericType.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,37 @@
#include <string>
#include <utility>

#include <symboltablebuilder/QualType.h>
#include <symboltablebuilder/Type.h>

#include "../../lib/json/json.hpp"

namespace spice::compiler {

// Typedefs
using TypeMapping = std::unordered_map</*typeName=*/std::string, /*concreteType=*/Type>;
using TypeMapping = std::unordered_map</*typeName=*/std::string, /*concreteType=*/QualType>;

class GenericType : public Type {
public:
// Constructors
explicit GenericType(const Type &type) : Type(type){};
explicit GenericType(const std::string &name) : Type(TY_GENERIC, name) {}
GenericType(const std::string &name, const std::vector<Type> &typeConditions)
GenericType(const std::string &name, const std::vector<QualType> &typeConditions)
: Type(TY_GENERIC, name), typeConditions(typeConditions) {}
GenericType() = default;

// Public methods
[[nodiscard]] bool checkConditionsOf(const Type &symbolType, bool ignoreArraySize = false,
bool ignoreSpecifiers = false) const;
[[nodiscard]] bool checkConditionsOf(const QualType &type, bool ignoreArraySize = false, bool ignoreSpecifiers = false) const;

// Public members
bool used = false;

// Json serializer/deserializer
NLOHMANN_DEFINE_TYPE_INTRUSIVE(GenericType, typeChain, typeConditions)

private:
// Members
std::vector<Type> typeConditions = {Type(TY_DYN)};
std::vector<QualType> typeConditions = {QualType(Type(TY_DYN))};

// Private methods
[[nodiscard]] bool checkTypeConditionOf(const Type &symbolType, bool ignoreArraySize, bool ignoreSpecifiers) const;
[[nodiscard]] bool checkTypeConditionOf(const QualType &symbolType, bool ignoreArraySize, bool ignoreSpecifiers) const;
};

} // namespace spice::compiler
5 changes: 0 additions & 5 deletions src/model/Struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#include <model/GenericType.h>
#include <model/StructBase.h>

#include "../../lib/json/json.hpp"

namespace spice::compiler {

class Struct : public StructBase {
Expand All @@ -27,9 +25,6 @@ class Struct : public StructBase {
// Public members
std::vector<Type> fieldTypes;
std::vector<Type> interfaceTypes;

// Json serializer/deserializer
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Struct, name, fieldTypes, templateTypes, interfaceTypes, genericSubstantiation, used)
};

} // namespace spice::compiler
2 changes: 1 addition & 1 deletion src/model/StructBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ std::string StructBase::getSignature(const std::string &name, const std::vector<
for (size_t i = 0; i < concreteTemplateTypes.size(); i++) {
if (i > 0)
templateTyStr << ",";
templateTyStr << concreteTemplateTypes.at(i).getName(false, true);
templateTyStr << concreteTemplateTypes.at(i).getName(false);
}
templateTyStr << ">";
}
Expand Down
2 changes: 1 addition & 1 deletion src/model/StructBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class StructBase {
// Public members
std::string name;
std::vector<GenericType> templateTypes;
std::unordered_map<std::string, Type> typeMapping;
std::unordered_map<std::string, QualType> typeMapping;
SymbolTableEntry *entry = nullptr;
Scope *scope = nullptr;
ASTNode *declNode;
Expand Down
3 changes: 1 addition & 2 deletions src/symboltablebuilder/Capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ namespace spice::compiler {
Capture::Capture(SymbolTableEntry *entry) : capturedEntry(entry) {
// Set the capture mode depending on the symbol type
// All types with guaranteed size <= 64 bit are captured by value, all others by reference.
const Type &type = entry->getType();
captureMode = type.isOneOf({TY_STRUCT, TY_INTERFACE}) ? BY_REFERENCE : BY_VALUE;
captureMode = entry->getType().isOneOf({TY_STRUCT, TY_INTERFACE}) ? BY_REFERENCE : BY_VALUE;
}

/**
Expand Down
112 changes: 112 additions & 0 deletions src/symboltablebuilder/QualType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) 2021-2024 ChilliBits. All rights reserved.

#include "QualType.h"

namespace spice::compiler {

/**
* Check for the matching compatibility of two types.
* Useful for struct and function matching as well as assignment type validation and function arg matching.
*
* @param otherType Type to compare against
* @param ignoreArraySize Ignore array sizes
* @param ignoreSpecifiers Ignore specifiers, except for pointer and reference types
* @param allowConstify Match when the types are the same, but the lhs type is more const restrictive than the rhs type
* @return Matching or not
*/
bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const {
// Compare type
if (!type.matches(otherType.type, ignoreArraySize))
return false;

// Ignore or compare specifiers
return ignoreSpecifiers || specifiers.match(otherType.specifiers, allowConstify);
}

/**
* Get the name of the symbol type as a string
*
* @param withSize Include the array size for sized types
* @param ignorePublic Ignore any potential public specifier
* @return Symbol type name
*/
std::string QualType::getName(bool withSize, bool ignorePublic) const { // NOLINT(misc-no-recursion)
std::stringstream name;

// Append the specifiers
const TypeSpecifiers defaultForSuperType = TypeSpecifiers::of(type.getSuperType());
if (!ignorePublic && specifiers.isPublic && !defaultForSuperType.isPublic)
name << "public ";
if (specifiers.isInline && !defaultForSuperType.isInline)
name << "inline ";
if (specifiers.isComposition && !defaultForSuperType.isComposition)
name << "compose ";
if (specifiers.isConst && !defaultForSuperType.isConst)
name << "const ";
if (specifiers.isHeap && !defaultForSuperType.isHeap)
name << "heap ";
if (specifiers.isSigned && !defaultForSuperType.isSigned)
name << "signed ";
if (!specifiers.isSigned && defaultForSuperType.isSigned)
name << "unsigned ";

// Loop through all chain elements
type.getName(name, withSize);

return name.str();
}

bool QualType::isConst() const { return specifiers.isConst; }

bool QualType::isSigned() const {
assert(isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_CHAR, TY_BOOL}));
return specifiers.isSigned;
}

bool QualType::isInline() const {
assert(isOneOf({TY_FUNCTION, TY_PROCEDURE}));
return specifiers.isInline;
}

bool QualType::isPublic() const {
assert(type.isPrimitive() /* Global variables */ || isOneOf({TY_FUNCTION, TY_PROCEDURE, TY_ENUM, TY_STRUCT, TY_INTERFACE}));
return specifiers.isPublic;
}

bool QualType::isHeap() const { return specifiers.isHeap; }

bool QualType::isConstRef() const { return specifiers.isConst && type.isRef(); }

QualType QualType::toNonConst() const {
QualType qualType = *this;
qualType.specifiers.isConst = false;
return qualType;
}

/**
* Check if a certain input type can be bound (assigned) to the current type.
*
* @param inputType Qualified type, which should be bound to the current type
* @param isTemporary Is the input type a temporary type
* @return Can be bound or not
*/
bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
return !isTemporary || inputType.type.isRef() || !type.isRef() || isConstRef();
}

/**
* Replace the base type with another one
*
* @param newBaseType New base type
* @return The new type
*/
QualType QualType::replaceBaseType(const QualType &newBaseType) const {
// Create new type
Type newType = type.replaceBaseType(newBaseType.getType());
// Create new specifiers
TypeSpecifiers newSpecifiers = specifiers.merge(newBaseType.specifiers);
// Return the new qualified type
return {newType, newSpecifiers};
}

} // namespace spice::compiler
46 changes: 46 additions & 0 deletions src/symboltablebuilder/QualType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2021-2024 ChilliBits. All rights reserved.

#pragma once

#include <utility>

#include <symboltablebuilder/Type.h>
#include <symboltablebuilder/TypeSpecifiers.h>

namespace spice::compiler {

class QualType {
public:
// Constructors
explicit QualType(Type type) : type(std::move(type)) {}
QualType(Type type, TypeSpecifiers specifiers) : type(std::move(type)), specifiers(specifiers) {}

// Public methods
[[nodiscard]] Type &getType() { return type; }
[[nodiscard]] const Type &getType() const { return type; }
[[nodiscard]] bool matches(const QualType &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const;
[[nodiscard]] std::string getName(bool withSize = false, bool ignorePublic = false) const;
[[nodiscard]] ALWAYS_INLINE bool is(SuperType superType) const { return type.is(superType); }
[[nodiscard]] ALWAYS_INLINE bool isOneOf(const std::initializer_list<SuperType> &superTypes) const {
return type.isOneOf(superTypes);
}
[[nodiscard]] bool isConst() const;
[[nodiscard]] bool isSigned() const;
[[nodiscard]] bool isInline() const;
[[nodiscard]] bool isPublic() const;
[[nodiscard]] bool isHeap() const;
[[nodiscard]] bool isConstRef() const;
[[nodiscard]] QualType toNonConst() const;
[[nodiscard]] bool canBind(const QualType &otherType, bool isTemporary) const;
[[nodiscard]] QualType replaceBaseType(const QualType &newBaseType) const;

private:
// Private members
Type type;
TypeSpecifiers specifiers;
};

// Make sure we have no unexpected increases in memory consumption
static_assert(sizeof(QualType) == 32);

} // namespace spice::compiler
Loading

0 comments on commit f5cd430

Please sign in to comment.