225 lines
6.8 KiB
C++
225 lines
6.8 KiB
C++
|
|
#include <sstream>
|
|
|
|
#include "types.h"
|
|
#include "binops.h"
|
|
|
|
namespace types {
|
|
int operator_precedence(BinOp& op) {
|
|
switch (op) {
|
|
case BinOp::Add:
|
|
case BinOp::Sub:
|
|
return 10;
|
|
|
|
case BinOp::LessThan:
|
|
case BinOp::GreaterThan:
|
|
return 20;
|
|
|
|
case BinOp::Assignment:
|
|
return 1000;
|
|
default:
|
|
return 1000;
|
|
}
|
|
}
|
|
|
|
std::string format_operator(BinOp& op) {
|
|
switch (op) {
|
|
case BinOp::Assignment:
|
|
return "=";
|
|
case BinOp::Add:
|
|
return "+";
|
|
case BinOp::Sub:
|
|
return "-";
|
|
case BinOp::LessThan:
|
|
return "<";
|
|
case BinOp::GreaterThan:
|
|
return ">";
|
|
default:
|
|
return "??";
|
|
}
|
|
}
|
|
|
|
std::string FundamentalType::formatted() {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
return "Int";
|
|
case FundamentalTypeKind::Bool:
|
|
return "Bool";
|
|
case FundamentalTypeKind::Char:
|
|
return "Char";
|
|
case FundamentalTypeKind::Void:
|
|
return "Void";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
|
|
llvm::Value* Type::add(codegen::Builder&, llvm::Value*, llvm::Value*) {
|
|
throw std::runtime_error("Invalid operation for this type");
|
|
}
|
|
|
|
llvm::Value* Type::sub(codegen::Builder&, llvm::Value*, llvm::Value*) {
|
|
throw std::runtime_error("Invalid operation for this type");
|
|
}
|
|
|
|
llvm::Value* Type::lt(codegen::Builder&, llvm::Value*, llvm::Value*) {
|
|
throw std::runtime_error("Invalid operation for this type");
|
|
}
|
|
|
|
llvm::Value* Type::gt(codegen::Builder&, llvm::Value*, llvm::Value*) {
|
|
throw std::runtime_error("Invalid operation for this type");
|
|
}
|
|
|
|
std::optional<std::shared_ptr<Type>> Type::return_type() {
|
|
return {};
|
|
}
|
|
|
|
bool Type::is_signed() {
|
|
false;
|
|
}
|
|
|
|
std::pair<llvm::Value*, std::shared_ptr<Type>> FundamentalType::load(codegen::Builder&, llvm::Value* ptr) {
|
|
auto self = std::make_shared<FundamentalType>(*this);
|
|
return std::pair(ptr, self);
|
|
}
|
|
|
|
llvm::Value* FundamentalType::add(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
case FundamentalTypeKind::Bool:
|
|
case FundamentalTypeKind::Char:
|
|
return builder.builder->CreateAdd(lhs, rhs, "add");
|
|
default:
|
|
throw std::runtime_error("Invalid type for add");
|
|
}
|
|
}
|
|
|
|
llvm::Value* FundamentalType::sub(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
case FundamentalTypeKind::Bool:
|
|
case FundamentalTypeKind::Char:
|
|
return builder.builder->CreateSub(lhs, rhs, "sub");
|
|
default:
|
|
throw std::runtime_error("Invalid type");
|
|
}
|
|
}
|
|
|
|
llvm::Value* FundamentalType::lt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
case FundamentalTypeKind::Bool:
|
|
case FundamentalTypeKind::Char:
|
|
return builder.builder->CreateCmp(llvm::CmpInst::Predicate::ICMP_SLT, lhs, rhs, "cmp");
|
|
default:
|
|
throw std::runtime_error("Invalid type");
|
|
}
|
|
}
|
|
|
|
llvm::Value* FundamentalType::gt(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
case FundamentalTypeKind::Bool:
|
|
case FundamentalTypeKind::Char:
|
|
return builder.builder->CreateCmp(llvm::CmpInst::Predicate::ICMP_SGT, lhs, rhs);
|
|
default:
|
|
throw std::runtime_error("Invalid type");
|
|
}
|
|
}
|
|
|
|
bool FundamentalType::is_signed() {
|
|
switch (this->m_ty) {
|
|
case FundamentalTypeKind::Int:
|
|
return true;
|
|
case FundamentalTypeKind::Bool:
|
|
case FundamentalTypeKind::Char:
|
|
return false;
|
|
default:
|
|
throw std::runtime_error("Invalid type");
|
|
}
|
|
}
|
|
|
|
std::string FunctionType::formatted() {
|
|
std::stringstream out{ "" };
|
|
out << "(";
|
|
|
|
int counter = 0;
|
|
for (auto& param : this->m_param_tys) {
|
|
if (counter++ > 0)
|
|
out << ", ";
|
|
out << param->formatted();
|
|
}
|
|
|
|
if (this->m_vararg) {
|
|
if (counter > 0)
|
|
out << ", ";
|
|
out << "...";
|
|
}
|
|
|
|
out << ") -> " << this->m_ret_ty->formatted();
|
|
return out.str();
|
|
}
|
|
|
|
std::optional<std::shared_ptr<Type>> FunctionType::return_type() {
|
|
return this->m_ret_ty;
|
|
}
|
|
|
|
std::pair<llvm::Value*, std::shared_ptr<Type>> FunctionType::load(codegen::Builder&, llvm::Value* ptr) {
|
|
auto self = std::make_shared<FunctionType>(*this);
|
|
return std::pair(ptr, self);
|
|
}
|
|
|
|
std::string PointerType::formatted() {
|
|
std::stringstream out{ "" };
|
|
out << this->m_inner->formatted() << "*";
|
|
return out.str();
|
|
}
|
|
|
|
std::pair<llvm::Value*, std::shared_ptr<Type>> PointerType::load(codegen::Builder& builder, llvm::Value* ptr) {
|
|
return std::pair(
|
|
builder.builder->CreateLoad(this->m_inner->codegen(builder), ptr),
|
|
this->m_inner
|
|
);
|
|
}
|
|
|
|
bool types_equal(std::shared_ptr<types::Type> type1, std::shared_ptr<types::Type> type2) {
|
|
if (type1->m_kind != type2->m_kind)
|
|
return false;
|
|
|
|
if (type1->m_kind == TypeKind::Fundamental) {
|
|
auto ty1 = dynamic_cast<FundamentalType*>(type1.get());
|
|
auto ty2 = dynamic_cast<FundamentalType*>(type2.get());
|
|
return ty1->m_ty == ty2->m_ty;
|
|
}
|
|
else if (type1->m_kind == TypeKind::Function) {
|
|
auto ty1 = dynamic_cast<FunctionType*>(type1.get());
|
|
auto ty2 = dynamic_cast<FunctionType*>(type2.get());
|
|
|
|
if (!types_equal(ty1->m_ret_ty, ty2->m_ret_ty))
|
|
return false;
|
|
if (ty1->m_vararg != ty2->m_vararg)
|
|
return false;
|
|
if (ty1->m_param_tys.size() != ty2->m_param_tys.size())
|
|
return false;
|
|
|
|
for (int i = 0; i < static_cast<int>(ty1->m_param_tys.size()); i++) {
|
|
auto param1 = ty1->m_param_tys[i];
|
|
auto param2 = ty2->m_param_tys[i];
|
|
if (!types_equal(param1, param2))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if (type1->m_kind == TypeKind::Pointer) {
|
|
auto ty1 = dynamic_cast<PointerType*>(type1.get());
|
|
auto ty2 = dynamic_cast<PointerType*>(type2.get());
|
|
|
|
return types_equal(ty1->m_inner, ty2->m_inner);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
} |