Compare commits

..

No commits in common. "4baeaff70514edfee0209952bf58d8d8233b471b" and "e3e0cd9f9f8e735cb69f521eaf5e3e40601f9fec" have entirely different histories.

11 changed files with 38 additions and 159 deletions

View File

@ -23,7 +23,6 @@ add_executable(${PROJECT_NAME}
src/codegen.cpp src/codegen.cpp
src/types.cpp src/types.cpp
src/typechecker.cpp src/typechecker.cpp
src/binops.cpp
) )
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Weffc++ -Wextra -Wpedantic -Werror) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Weffc++ -Wextra -Wpedantic -Werror)

View File

@ -7,7 +7,6 @@
#include "codegen.h" #include "codegen.h"
#include "types.h" #include "types.h"
#include "binops.h"
#include "tokens.h" #include "tokens.h"
#include "typechecker.h" #include "typechecker.h"

View File

@ -1,63 +0,0 @@
#include "binops.h"
namespace types {
std::vector<BinopDefinition> create_binops() {
std::vector<BinopDefinition> definitions{};
auto int_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
for (auto& ty : { int_ty, char_ty, bool_ty }) {
// Arithmetic binops
definitions.push_back(BinopDefinition{
ty, types::BinOp::Add, ty,
ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateAdd(lhs, rhs, "add");
} });
definitions.push_back(BinopDefinition{
ty, types::BinOp::Sub, ty,
ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateSub(lhs, rhs, "sub");
} });
// Comparisons
definitions.push_back(BinopDefinition{
ty, types::BinOp::LessThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSLE(lhs, rhs, "icmpsle");
} });
definitions.push_back(BinopDefinition{
ty, types::BinOp::GreaterThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSGT(lhs, rhs, "icmpsgt");
} });
}
return definitions;
}
std::optional<BinopDefinition> find_binop(
std::vector<BinopDefinition>& binops,
std::shared_ptr<types::Type> lhs,
BinOp op,
std::shared_ptr<types::Type> rhs) {
for (auto& binop : binops) {
if (binop.op != op) {
continue;
}
if (!types_equal(lhs, binop.lhs) || !types_equal(rhs, binop.rhs)) {
continue;
}
return binop;
}
return {};
}
}

View File

@ -1,39 +0,0 @@
#ifndef BINOP_H
#define BINOP_H
#include <memory>
#include "types.h"
namespace types {
enum class BinOp {
Assignment,
Add,
Sub,
LessThan,
GreaterThan,
};
int operator_precedence(BinOp& op);
std::string format_operator(BinOp& op);
struct BinopDefinition {
std::shared_ptr<Type> lhs;
BinOp op;
std::shared_ptr<Type> rhs;
std::shared_ptr<Type> result;
llvm::Value* (*codegen)(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs);
};
std::vector<BinopDefinition> create_binops();
std::optional<BinopDefinition> find_binop(
std::vector<BinopDefinition>& binops,
std::shared_ptr<types::Type> lhs,
BinOp op,
std::shared_ptr<types::Type> rhs);
}
#endif

View File

@ -11,7 +11,7 @@
namespace codegen { namespace codegen {
Scope Scope::with_lvalue() { Scope Scope::with_lvalue() {
return Scope{ this->binops, this->values, true }; return Scope{ this->values, true };
} }
} }
@ -67,18 +67,27 @@ namespace AST {
case types::BinOp::Assignment: case types::BinOp::Assignment:
builder.builder->CreateStore(rhs.value, lhs.value, false); builder.builder->CreateStore(rhs.value, lhs.value, false);
return rhs; return rhs;
case types::BinOp::Add:
return codegen::StackValue{
lhs.ty->add(builder, lhs.value, rhs.value),
lhs.ty
};
case types::BinOp::Sub:
return codegen::StackValue{
lhs.ty->sub(builder, lhs.value, rhs.value),
lhs.ty
};
case types::BinOp::LessThan:
return codegen::StackValue{
lhs.ty->lt(builder, lhs.value, rhs.value),
std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Bool),
};
case types::BinOp::GreaterThan:
return codegen::StackValue{
lhs.ty->gt(builder, lhs.value, rhs.value),
std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Bool),
};
default: default:
auto binop = types::find_binop(
scope.binops,
lhs.ty,
this->m_binop,
rhs.ty);
if (binop) {
return codegen::StackValue{
binop->codegen(builder, lhs.value, rhs.value),
binop->result
};
}
throw CompileError("invalid binop", this->m_meta); throw CompileError("invalid binop", this->m_meta);
} }
} }

View File

@ -8,7 +8,6 @@
#include "builder.h" #include "builder.h"
#include "types.h" #include "types.h"
#include "binops.h"
#include "tokens.h" #include "tokens.h"
namespace codegen { namespace codegen {
@ -18,8 +17,6 @@ namespace codegen {
}; };
struct Scope { struct Scope {
std::vector<types::BinopDefinition>& binops;
std::map<std::string, StackValue> values; std::map<std::string, StackValue> values;
bool is_lvalue; bool is_lvalue;

View File

@ -98,8 +98,6 @@ std::optional<CompileOutput> compile(std::string_view in_filename) {
// Perform static analysis // Perform static analysis
typecheck::State typecheck_state{}; typecheck::State typecheck_state{};
typecheck_state.binops = types::create_binops();
typecheck::Scope typecheck_scope{}; typecheck::Scope typecheck_scope{};
for (auto& tls : statements) { for (auto& tls : statements) {
std::cout << tls->formatted() << std::endl; std::cout << tls->formatted() << std::endl;
@ -116,11 +114,7 @@ std::optional<CompileOutput> compile(std::string_view in_filename) {
return {}; return {};
} }
codegen::Scope cg_scope{ codegen::Scope cg_scope{};
.binops = typecheck_state.binops,
.values = {},
.is_lvalue = false,
};
// Compile parsed output // Compile parsed output
try { try {

View File

@ -85,32 +85,9 @@ namespace AST {
auto lhs_ty = this->m_lhs->typecheck(state, scope, {}); auto lhs_ty = this->m_lhs->typecheck(state, scope, {});
auto rhs_ty = this->m_rhs->typecheck(state, scope, {}); auto rhs_ty = this->m_rhs->typecheck(state, scope, {});
if (this->m_binop == types::BinOp::Assignment) { // TODO actually check binop types properly
return lhs_ty;
}
auto binop = types::find_binop( return lhs_ty;
state.binops,
lhs_ty,
this->m_binop,
rhs_ty
);
if (binop) {
return binop->result;
}
// TODO check for binops that may be implicitly castable
state.errors.push_back(CompileError(
"No suitable binop between "
+ lhs_ty->formatted() + " "
+ types::format_operator(this->m_binop) + " "
+ rhs_ty->formatted(),
this->m_meta));
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Void } };
} }
std::shared_ptr<types::Type> FunctionCallExpression::typecheck( std::shared_ptr<types::Type> FunctionCallExpression::typecheck(
@ -173,12 +150,10 @@ namespace AST {
} }
void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto bool_ty = std::shared_ptr<types::Type>{ auto bool_ty_ptr = new types::FundamentalType{ types::FundamentalTypeKind::Bool };
new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; this->m_condition->typecheck(state, scope, std::shared_ptr<types::Type>{ bool_ty_ptr });
auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty);
auto check_res = check_type(expr_ty, bool_ty); // TODO check that condition really is a boolean
this->m_condition = handle_res(std::move(this->m_condition), check_res, state);
this->m_then->typecheck(state, scope); this->m_then->typecheck(state, scope);
if (this->m_else) { if (this->m_else) {

View File

@ -4,7 +4,6 @@
#include <map> #include <map>
#include "types.h" #include "types.h"
#include "binops.h"
#include "errors.h" #include "errors.h"
namespace typecheck { namespace typecheck {
@ -14,7 +13,6 @@ namespace typecheck {
}; };
struct State { struct State {
std::vector<types::BinopDefinition> binops;
std::vector<CompileError> errors; std::vector<CompileError> errors;
}; };
} }

View File

@ -2,7 +2,6 @@
#include <sstream> #include <sstream>
#include "types.h" #include "types.h"
#include "binops.h"
namespace types { namespace types {
int operator_precedence(BinOp& op) { int operator_precedence(BinOp& op) {

View File

@ -7,6 +7,17 @@
#include <memory> #include <memory>
namespace types { namespace types {
enum class BinOp {
Assignment,
Add,
Sub,
LessThan,
GreaterThan,
};
int operator_precedence(BinOp& op);
std::string format_operator(BinOp& op);
enum class TypeKind { enum class TypeKind {
Fundamental, Fundamental,
Function, Function,