Compare commits

..

7 Commits

9 changed files with 194 additions and 24 deletions

View File

@ -49,6 +49,18 @@ namespace AST {
return out.str();
}
std::string RefExpression::formatted() {
std::stringstream out{ "" };
out << "&" << this->m_expr->formatted();
return out.str();
}
std::string DerefExpression::formatted() {
std::stringstream out{ "" };
out << "*" << this->m_expr->formatted();
return out.str();
}
std::string ExpressionStatement::formatted() {
std::stringstream out{ "" };
out << this->m_expr->formatted();

View File

@ -39,6 +39,7 @@ namespace AST {
virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) = 0;
};
/// @brief Any integer literal
class IntLiteralExpression : public Expression {
private:
int m_value;
@ -61,6 +62,7 @@ namespace AST {
) override;
};
/// @brief i.e. "contents"
class StringLiteralExpression : public Expression {
private:
std::string m_value;
@ -76,6 +78,7 @@ namespace AST {
) override;
};
/// @brief Anything that references by value
class ValueReferenceExpression : public Expression {
private:
std::string m_name;
@ -91,6 +94,7 @@ namespace AST {
) override;
};
/// @brief Any binary operation (i.e. lhs + rhs)
class BinaryOperationExpression : public Expression {
private:
std::unique_ptr<Expression> m_lhs;
@ -117,6 +121,7 @@ namespace AST {
) override;
};
/// @brief Same as fn()/// @brief
class FunctionCallExpression : public Expression {
private:
std::unique_ptr<Expression> m_fn_expr;
@ -140,6 +145,7 @@ namespace AST {
) override;
};
/// @brief Same as (type) value
class CastExpression : public Expression {
private:
std::shared_ptr<types::Type> m_ty;
@ -163,6 +169,48 @@ namespace AST {
) override;
};
/// @brief Same as &value
class RefExpression : public Expression {
private:
std::unique_ptr<Expression> m_expr;
public:
RefExpression(
token::Metadata meta,
std::unique_ptr<Expression> expr)
: Expression{ meta }
, m_expr{ std::move(expr) } {
}
virtual ~RefExpression() override = default;
virtual std::string formatted() override;
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty
) override;
};
/// @brief Same as *value
class DerefExpression : public Expression {
private:
std::unique_ptr<Expression> m_expr;
public:
DerefExpression(
token::Metadata meta,
std::unique_ptr<Expression> expr)
: Expression{ meta }
, m_expr{ std::move(expr) } {
}
virtual ~DerefExpression() override = default;
virtual std::string formatted() override;
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty
) override;
};
class ReturnStatement : public Statement {
private:

View File

@ -16,45 +16,69 @@ namespace types {
for (auto& ty : { int_ty, char_ty, bool_ty }) {
definitions.push_back(BinopDefinition{
ty, types::BinOp::Add, ty,
ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateAdd(lhs, rhs, "add");
} });
},
[](BinopDefinition& def, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {return def.lhs;}
});
definitions.push_back(BinopDefinition{
ty, types::BinOp::Sub, ty,
ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateSub(lhs, rhs, "sub");
} });
},
[](BinopDefinition& def, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {return def.lhs;}
});
}
// Signed comparisons
for (auto& ty : { int_ty }) {
definitions.push_back(BinopDefinition{
ty, types::BinOp::LessThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSLT(lhs, rhs, "icmpslt");
} });
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
}
});
definitions.push_back(BinopDefinition{
ty, types::BinOp::GreaterThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSGT(lhs, rhs, "icmpsgt");
} });
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
}
});
}
// Unsigned comparisons
for (auto& ty : { bool_ty, char_ty }) {
definitions.push_back(BinopDefinition{
ty, types::BinOp::LessThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpULT(lhs, rhs, "icmpslt");
} });
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
}
});
definitions.push_back(BinopDefinition{
ty, types::BinOp::GreaterThan, ty,
bool_ty, [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpUGT(lhs, rhs, "icmpsgt");
} });
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
}
});
}
return definitions;

View File

@ -22,8 +22,8 @@ namespace types {
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::shared_ptr<Type>(*result)(BinopDefinition& def, std::shared_ptr<Type> lhs, std::shared_ptr<Type> rhs);
};
std::vector<BinopDefinition> create_binops();

View File

@ -74,7 +74,7 @@ namespace AST {
if (binop) {
return codegen::StackValue{
binop->codegen(builder, lhs.value, rhs.value),
binop->result
binop->result(*binop, lhs.ty, rhs.ty)
};
}
throw CompileError("invalid binop", this->m_meta);
@ -111,6 +111,26 @@ namespace AST {
return expr;
}
codegen::StackValue RefExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) {
auto with_lvalue = scope.with_lvalue();
return this->m_expr->codegen(builder, with_lvalue);
}
codegen::StackValue DerefExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) {
auto value = this->m_expr->codegen(builder, scope);
if (value.ty->m_kind == types::TypeKind::Pointer) {
auto loaded = value.ty->load(builder, value.value);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
else {
throw new CompileError("Tried to deref a non-pointer!", this->m_meta);
}
}
void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) {
if (!builder.block)
return;
@ -211,12 +231,17 @@ namespace AST {
int counter = 0;
for (auto& param : this->m_params) {
auto param_ty_ptr = param_ty_ptrs[counter];
builder.builder->SetInsertPoint(BB);
auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder));
auto param_ty_ptr = std::shared_ptr<types::Type>{
new types::PointerType { param_ty_ptrs[counter]}
};
auto arg = function->getArg(counter++);
builder.builder->CreateStore(arg, arg_ptr);
if (param.first) {
arg->setName(*param.first);
inner_scope.values[*param.first] = codegen::StackValue{
arg,
arg_ptr,
param_ty_ptr,
};
}
@ -227,6 +252,8 @@ namespace AST {
}
}
builder.builder->CreateRetVoid();
llvm::verifyFunction(*function);
builder.block = nullptr;

View File

@ -101,6 +101,14 @@ namespace parsing {
try {
auto before_meta = inner.metadata();
if (inner.peek().content == "(") {
inner.next();
auto expr = parse_expression(inner).unwrap();
inner.expect(token::Type::Symbol, ")");
stream.m_position = inner.m_position;
return expr;
}
if (auto cast = parse_cast(inner); cast.ok()) {
auto expr = parse_expression(inner).unwrap();
stream.m_position = inner.m_position;
@ -112,6 +120,22 @@ namespace parsing {
}
};
}
else if (inner.peek().content == "&") {
inner.next();
auto expr = parse_primary_expression(inner).unwrap();
stream.m_position = inner.m_position;
return std::unique_ptr<AST::Expression> {
new AST::RefExpression(before_meta + inner.metadata(), std::move(expr))
};
}
else if (inner.peek().content == "*") {
inner.next();
auto expr = parse_primary_expression(inner).unwrap();
stream.m_position = inner.m_position;
return std::unique_ptr<AST::Expression> {
new AST::DerefExpression(before_meta + inner.metadata(), std::move(expr))
};
}
auto plain_expr = parse_plain_expression(inner);
while (inner.peek().content == "(") {

View File

@ -133,7 +133,7 @@ namespace AST {
);
if (binop) {
return binop->result;
return binop->result(*binop, lhs_ty, rhs_ty);
}
// If that fails, try to find binop that matches on one side perfectly
@ -143,7 +143,7 @@ namespace AST {
if (expected_ty) {
// Skip any binops that would not be immediately assignable to
// the expected type
if (!types::types_equal(binop.result, *expected_ty)) {
if (!types::types_equal(binop.result(binop, lhs_ty, rhs_ty), *expected_ty)) {
continue;
}
}
@ -153,7 +153,7 @@ namespace AST {
// Skip if not implicitly castable to lhs
continue;
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_res, state);
return binop.result;
return binop.result(binop, lhs_ty, rhs_ty);
}
else if (types::types_equal(binop.rhs, rhs_ty)) {
auto lhs_res = check_type(state, lhs_ty, binop.lhs);
@ -161,7 +161,7 @@ namespace AST {
// Skip if not implicitly castable to rhs
continue;
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_res, state);
return binop.result;
return binop.result(binop, lhs_ty, rhs_ty);
}
}
@ -171,7 +171,7 @@ namespace AST {
if (expected_ty) {
// Skip any binops that would not even be implicitly castable to
// the expected result
auto result_res = check_type(state, binop.result, *expected_ty);
auto result_res = check_type(state, binop.result(binop, lhs_ty, rhs_ty), *expected_ty);
if (!result_res.ok())
continue;
}
@ -179,7 +179,7 @@ namespace AST {
auto rhs_result = check_type(state, rhs_ty, binop.rhs);
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_result, state);
this->m_rhs = handle_res(std::move(this->m_rhs), lhs_result, state);
return binop.result;
return binop.result(binop, lhs_ty, rhs_ty);
}
// No suitable binops found :(
@ -253,6 +253,35 @@ namespace AST {
} };
}
std::shared_ptr<types::Type> RefExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
auto expr_ty = this->m_expr->typecheck(state, scope, {});
return std::shared_ptr<types::Type> {
new types::PointerType{ expr_ty }
};
}
std::shared_ptr<types::Type> DerefExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
auto expr_ty = this->m_expr->typecheck(state, scope, {});
if (expr_ty->m_kind != types::TypeKind::Pointer) {
state.errors.push_back(
CompileError("Tried to deref " + expr_ty->formatted(), this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
}
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return ptr_ty->m_inner;
}
void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);
if (scope.return_ty) {

View File

@ -18,6 +18,8 @@ namespace types {
Bool,
Char,
Void,
/// @brief Mainly used for binop resolution
Any,
};
class Type {

8
test.c
View File

@ -6,9 +6,13 @@ int fibonacci(int n) {
return fibonacci(n - 1) + fibonacci(n - 2);
}
void modifyvalue(char* otus) {
*otus = 20;
}
int main() {
printf("10th fibonacci number is %d!", fibonacci(10));
char res = 0;
res = 15;
char res = 10;
modifyvalue(&res);
return res;
}