Skip to content

Commit

Permalink
feat: Add basic pointer arithmetic
Browse files Browse the repository at this point in the history
Part of #56

You can now do `pointer + number`
  • Loading branch information
Gashmob committed Feb 8, 2025
1 parent d437f2f commit 9c7a15d
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 15 deletions.
2 changes: 2 additions & 0 deletions include/filc/llvm/IRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

namespace filc {
class IRGenerator final: public Visitor<llvm::Value *> {
friend class CalculBuilder;

public:
explicit IRGenerator(const std::string &filename, const Environment *environment);

Expand Down
20 changes: 15 additions & 5 deletions include/filc/validation/CalculValidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "filc/grammar/Type.h"
#include "filc/validation/Environment.h"

#include <memory>
#include <string>

Expand All @@ -34,18 +35,27 @@ class CalculValidator {
public:
explicit CalculValidator(Environment *environment);

[[nodiscard]] auto isCalculValid(const std::shared_ptr<AbstractType> &left_type, const std::string &op,
const std::shared_ptr<AbstractType> &right_type) const -> std::shared_ptr<AbstractType>;
[[nodiscard]] auto isCalculValid(
const std::shared_ptr<AbstractType> &left_type,
const std::string &op,
const std::shared_ptr<AbstractType> &right_type
) const -> std::shared_ptr<AbstractType>;

private:
Environment *_environment;

[[nodiscard]] auto isNumericOperatorValid(const std::shared_ptr<AbstractType> &left_type, const std::string &op) const -> std::shared_ptr<AbstractType>;
[[nodiscard]] auto
isNumericOperatorValid(const std::shared_ptr<AbstractType> &left_type, const std::string &op) const
-> std::shared_ptr<AbstractType>;

[[nodiscard]] auto isBoolOperatorValid(const std::string &op) const -> std::shared_ptr<AbstractType>;

[[nodiscard]] auto isPointerOperatorValid(const std::string &op) const -> std::shared_ptr<AbstractType>;
[[nodiscard]] auto isPointerOperatorValid(
const std::string &op,
const std::shared_ptr<AbstractType> &left_type,
const std::shared_ptr<AbstractType> &right_type
) const -> std::shared_ptr<AbstractType>;
};
}
} // namespace filc

#endif // FILC_CALCULVALIDATOR_H
15 changes: 15 additions & 0 deletions src/llvm/CalculBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,21 @@ auto CalculBuilder::buildPointer(const BinaryCalcul *calcul) const -> llvm::Valu
"pointer_inequality"
);
}
if (operation == "+") {
const auto left_type = calcul->getLeftExpression()->getType();
const auto left_pointer_type = std::dynamic_pointer_cast<PointerType>(left_type);
if (left_pointer_type == nullptr) {
throw std::logic_error("Left operand of 'pointer +' is not a pointer");
}

const auto add = _builder->CreateGEP(
left_pointer_type->getPointedType()->getLLVMType(_generator->_llvm_context.get()),
calcul->getLeftExpression()->acceptIRVisitor(_generator),
calcul->getRightExpression()->acceptIRVisitor(_generator),
"pointer_add"
);
return add;
}
throw buildError(calcul);
}

Expand Down
41 changes: 31 additions & 10 deletions src/validation/CalculValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ auto CalculValidator::isCalculValid(
const std::string &op,
const std::shared_ptr<AbstractType> &right_type
) const -> std::shared_ptr<AbstractType> {
if (left_type != right_type) {
return nullptr;
}
const auto type = left_type->getName();
const auto left_name = left_type->getName();
const auto right_name = right_type->getName();

const std::vector<std::string> numeric_type = {
"i8",
Expand All @@ -54,16 +52,17 @@ auto CalculValidator::isCalculValid(
"f32",
"f64",
};
if (std::find(numeric_type.begin(), numeric_type.end(), type) != numeric_type.end()) {
if (std::find(numeric_type.begin(), numeric_type.end(), left_name) != numeric_type.end()
&& left_type == right_type) {
return isNumericOperatorValid(left_type, op);
}

if (type == "bool") {
if (left_name == "bool" && left_type == right_type) {
return isBoolOperatorValid(op);
}

if (type[type.length() - 1] == '*') { // A pointer
return isPointerOperatorValid(op);
if (left_name[left_name.length() - 1] == '*') { // A pointer
return isPointerOperatorValid(op, left_type, right_type);
}

// We don't know what it is, so we assert it cannot be done
Expand Down Expand Up @@ -94,10 +93,32 @@ auto CalculValidator::isBoolOperatorValid(const std::string &op) const -> std::s
return nullptr;
}

auto CalculValidator::isPointerOperatorValid(const std::string &op) const -> std::shared_ptr<AbstractType> {
if (op == "==" || op == "!=") {
auto CalculValidator::isPointerOperatorValid(
const std::string &op,
const std::shared_ptr<AbstractType> &left_type,
const std::shared_ptr<AbstractType> &right_type
) const -> std::shared_ptr<AbstractType> {
if ((op == "==" || op == "!=") && left_type == right_type) {
return _environment->getType("bool");
}

if (op == "+") {
const std::vector<std::string> integer_type = {
"i8",
"i16",
"i32",
"i64",
"i128",
"u8",
"u16",
"u32",
"u64",
"u128",
};
if (std::find(integer_type.begin(), integer_type.end(), right_type->getName()) != integer_type.end()) {
return left_type;
}
}

return nullptr;
}
4 changes: 4 additions & 0 deletions tests/e2e/llvm_ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ TEST(ir_dump, pointer_address_program) {
ASSERT_EQ(3, getProgramResult("val foo = new i32(3);**&*&foo"));
}

TEST(ir_dump, pointer_arithmetic) {
ASSERT_EQ(3, getProgramResult("val foo = new i32(2);val bar = new i32(3);*(foo + 1)"));
}

TEST(ir_dump, array_program) {
ASSERT_EQ(2, getProgramResult("val foo = [1, 2, 3];foo[1]"));
ASSERT_EQ(6, getProgramResult("[4, 5, 6][2]"));
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/validation/CalculValidatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ TEST(CalculValidator, validPointer) {
->getName()
.c_str()
);

ASSERT_STREQ(
"bool*",
validator.isCalculValid(std::make_shared<filc::PointerType>(env->getType("bool")), "+", env->getType("i32"))
->getName()
.c_str()
);
}

TEST(CalculValidator, invalidUnknown) {
Expand Down

0 comments on commit 9c7a15d

Please sign in to comment.