#include #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> Type::return_type() { return {}; } bool Type::is_signed() { false; } std::pair> FundamentalType::load(codegen::Builder&, llvm::Value* ptr) { auto self = std::make_shared(*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> FunctionType::return_type() { return this->m_ret_ty; } std::pair> FunctionType::load(codegen::Builder&, llvm::Value* ptr) { auto self = std::make_shared(*this); return std::pair(ptr, self); } std::string PointerType::formatted() { std::stringstream out{ "" }; out << this->m_inner->formatted() << "*"; return out.str(); } std::pair> 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 type1, std::shared_ptr type2) { if (type1->m_kind != type2->m_kind) return false; if (type1->m_kind == TypeKind::Fundamental) { auto ty1 = dynamic_cast(type1.get()); auto ty2 = dynamic_cast(type2.get()); return ty1->m_ty == ty2->m_ty; } else if (type1->m_kind == TypeKind::Function) { auto ty1 = dynamic_cast(type1.get()); auto ty2 = dynamic_cast(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(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(type1.get()); auto ty2 = dynamic_cast(type2.get()); return types_equal(ty1->m_inner, ty2->m_inner); } else { return false; } } }