Keep working on type checker
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "../lexer/lexer.hpp"
|
#include "../lexer/lexer.hpp"
|
||||||
|
#include "../typechecker/type.hpp"
|
||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ namespace Solstice {
|
|||||||
std::vector<Node> children;
|
std::vector<Node> children;
|
||||||
std::variant<Literal, std::string> data;
|
std::variant<Literal, std::string> data;
|
||||||
|
|
||||||
|
PossibleType ptype;
|
||||||
|
|
||||||
Node() = delete;
|
Node() = delete;
|
||||||
Node(NodeType type) : type(type) {}
|
Node(NodeType type) : type(type) {}
|
||||||
Node(NodeType type, const std::vector<Node>& children) : type(type), children(children) {}
|
Node(NodeType type, const std::vector<Node>& children) : type(type), children(children) {}
|
||||||
|
|||||||
@@ -1,15 +1,55 @@
|
|||||||
#include "type.hpp"
|
#include "type.hpp"
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
|
std::optional<std::map<std::string, Type>> Type::getObject() const {
|
||||||
|
if (std::holds_alternative<std::map<std::string, Type>>(fields)) {
|
||||||
|
return std::get<std::map<std::string, Type>>(fields);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::optional<std::vector<Type>> Type::getTuple() const {
|
||||||
|
if (std::holds_alternative<std::vector<Type>>(fields)) {
|
||||||
|
return std::get<std::vector<Type>>(fields);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::optional<Type> Type::getArrayOrPointer() const {
|
||||||
|
if (std::holds_alternative<std::shared_ptr<Type>>(fields)) {
|
||||||
|
return *std::get<std::shared_ptr<Type>>(fields);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const Type& left, const Type& right) {
|
bool operator==(const Type& left, const Type& right) {
|
||||||
if (left.type != right.type) {
|
if (left.type != right.type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (left.type == BaseType::Object && left.fields != right.fields) {
|
switch (left.type) {
|
||||||
return false;
|
case BaseType::Object: {
|
||||||
|
auto leftObject = left.getObject();
|
||||||
|
auto rightObject = right.getObject();
|
||||||
|
|
||||||
|
return *leftObject == *rightObject;
|
||||||
|
}
|
||||||
|
case BaseType::Tuple: {
|
||||||
|
auto leftTuple = left.getTuple();
|
||||||
|
auto rightTuple = right.getTuple();
|
||||||
|
|
||||||
|
return *leftTuple == *rightTuple;
|
||||||
|
}
|
||||||
|
case BaseType::Array:
|
||||||
|
case BaseType::Pointer: {
|
||||||
|
auto leftType = left.getArrayOrPointer();
|
||||||
|
auto rightType = right.getArrayOrPointer();
|
||||||
|
|
||||||
|
return *leftType == *rightType;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const TypePair& left, const TypePair& right) {
|
bool operator==(const TypePair& left, const TypePair& right) {
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
enum class BaseType {
|
enum class BaseType {
|
||||||
None, Int, Double, String, Char, Bool, Array, Pointer, Object
|
None, Int, Double, String, Char, Bool, Tuple, Array, Pointer, Object
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Operator {
|
enum class Operator {
|
||||||
@@ -16,7 +19,20 @@ namespace Solstice {
|
|||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
BaseType type = BaseType::None;
|
BaseType type = BaseType::None;
|
||||||
std::map<std::string, Type> fields; // use map for ordering
|
std::variant<
|
||||||
|
// object
|
||||||
|
std::map<std::string, Type>, // use map for ordering
|
||||||
|
// tuple
|
||||||
|
std::vector<Type>,
|
||||||
|
// array/pointer
|
||||||
|
std::shared_ptr<Type>,
|
||||||
|
// anything else
|
||||||
|
std::nullopt_t
|
||||||
|
> fields = std::nullopt;
|
||||||
|
|
||||||
|
std::optional<std::map<std::string, Type>> getObject() const;
|
||||||
|
std::optional<std::vector<Type>> getTuple() const;
|
||||||
|
std::optional<Type> getArrayOrPointer() const;
|
||||||
|
|
||||||
Type() = delete;
|
Type() = delete;
|
||||||
Type(BaseType type) : type(type) {}
|
Type(BaseType type) : type(type) {}
|
||||||
@@ -39,12 +55,33 @@ namespace std {
|
|||||||
struct hash<Solstice::Type> {
|
struct hash<Solstice::Type> {
|
||||||
size_t operator()(const Solstice::Type& t) const {
|
size_t operator()(const Solstice::Type& t) const {
|
||||||
size_t output = std::hash<int>{}((int)t.type);
|
size_t output = std::hash<int>{}((int)t.type);
|
||||||
for (const auto& [key, value] : t.fields) {
|
switch (t.type) {
|
||||||
size_t keyHash = std::hash<std::string>{}(key);
|
case Solstice::BaseType::Object: {
|
||||||
size_t valHash = std::hash<Solstice::Type>{}(value);
|
auto object = t.getObject();
|
||||||
|
for (const auto& [key, value] : *object) {
|
||||||
output ^= keyHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
size_t keyHash = std::hash<std::string>{}(key);
|
||||||
output ^= valHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
size_t valHash = std::hash<Solstice::Type>{}(value);
|
||||||
|
|
||||||
|
output ^= keyHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
||||||
|
output ^= valHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Solstice::BaseType::Tuple: {
|
||||||
|
auto tuple = t.getTuple();
|
||||||
|
for (const auto& type : *tuple) {
|
||||||
|
size_t typeHash = std::hash<Solstice::Type>{}(type);
|
||||||
|
output ^= typeHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Solstice::BaseType::Array:
|
||||||
|
case Solstice::BaseType::Pointer: {
|
||||||
|
auto type = t.getArrayOrPointer();
|
||||||
|
size_t typeHash = std::hash<Solstice::Type>{}(*type);
|
||||||
|
output ^= typeHash + 0x9e3779b97f4a7c15ULL + (output << 6) + (output >> 2);
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -66,6 +103,9 @@ namespace Solstice {
|
|||||||
|
|
||||||
struct PossibleType {
|
struct PossibleType {
|
||||||
std::unordered_set<Type> possiblities;
|
std::unordered_set<Type> possiblities;
|
||||||
|
|
||||||
|
PossibleType() = default;
|
||||||
|
PossibleType(const std::unordered_set<Type>& possiblities) : possiblities(possiblities) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "typechecker.hpp"
|
#include "typechecker.hpp"
|
||||||
|
#include "type.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
@@ -68,5 +70,71 @@ namespace Solstice {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkLiteralNodeType(Node& node) {
|
||||||
|
auto literal = node.getLiteral();
|
||||||
|
if (!literal.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME literal node does not contain literal");
|
||||||
|
}
|
||||||
|
switch (literal->type) {
|
||||||
|
case LiteralType::None:
|
||||||
|
node.ptype = {{BaseType::None}};
|
||||||
|
break;
|
||||||
|
case LiteralType::String:
|
||||||
|
node.ptype = {{BaseType::String}};
|
||||||
|
break;
|
||||||
|
case LiteralType::Int:
|
||||||
|
node.ptype = {{BaseType::Int}};
|
||||||
|
break;
|
||||||
|
case LiteralType::Double:
|
||||||
|
node.ptype = {{BaseType::Double}};
|
||||||
|
break;
|
||||||
|
case LiteralType::Bool:
|
||||||
|
node.ptype = {{BaseType::Bool}};
|
||||||
|
break;
|
||||||
|
case LiteralType::Char:
|
||||||
|
node.ptype = {{BaseType::Char}};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkIdentifierNodeType(Node& node) {
|
||||||
|
auto identifier = node.getIdentifier();
|
||||||
|
if (!identifier.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME identifier node does not contain identifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variables.find(*identifier) == variables.end()) {
|
||||||
|
throw std::runtime_error("unknown variable " + *identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.ptype = variables[*identifier];
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkTupleNodeType(Node& node) {}
|
||||||
|
|
||||||
|
void TypeChecker::checkNodeType(Node& node) {
|
||||||
|
switch (node.type) {
|
||||||
|
case NodeType::Root:
|
||||||
|
node.ptype = {{}}; // no possible types for root node
|
||||||
|
break;
|
||||||
|
case NodeType::Literal:
|
||||||
|
checkLiteralNodeType(node);
|
||||||
|
break;
|
||||||
|
case NodeType::Expression:
|
||||||
|
checkNodeType(node.children[0]);
|
||||||
|
break;
|
||||||
|
case NodeType::Identifier:
|
||||||
|
checkIdentifierNodeType(node);
|
||||||
|
break;
|
||||||
|
case NodeType::Tuple:
|
||||||
|
checkTupleNodeType(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeChecker::checkTypes() {
|
||||||
|
checkNodeType(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
class TypeChecker {
|
class TypeChecker {
|
||||||
std::unordered_map<std::string, Type> variables;
|
std::unordered_map<std::string, PossibleType> variables;
|
||||||
std::unordered_map<std::string, Type> types;
|
std::unordered_map<std::string, Type> types;
|
||||||
|
|
||||||
std::unordered_map<TypePair, Type> addOverloads;
|
std::unordered_map<TypePair, Type> addOverloads;
|
||||||
@@ -25,6 +25,12 @@ namespace Solstice {
|
|||||||
|
|
||||||
void initOverloads();
|
void initOverloads();
|
||||||
|
|
||||||
|
void checkLiteralNodeType(Node& node);
|
||||||
|
void checkIdentifierNodeType(Node& node);
|
||||||
|
void checkTupleNodeType(Node& node);
|
||||||
|
|
||||||
|
void checkNodeType(Node& node);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TypeChecker() = delete;
|
TypeChecker() = delete;
|
||||||
|
|||||||
Reference in New Issue
Block a user