From 78c5ab4c258e430026319f892035162fe8ff2923 Mon Sep 17 00:00:00 2001 From: Sofia Date: Tue, 14 Apr 2026 00:01:33 +0300 Subject: [PATCH] Add ref and deref --- src/ast.cpp | 12 ++++++++++++ src/ast.h | 48 +++++++++++++++++++++++++++++++++++++++++++++ src/codegen.cpp | 21 ++++++++++++++++++++ src/typechecker.cpp | 29 +++++++++++++++++++++++++++ test.c | 3 ++- 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/ast.cpp b/src/ast.cpp index c17ae76..38b6a5f 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -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(); diff --git a/src/ast.h b/src/ast.h index a5234b7..2528c17 100644 --- a/src/ast.h +++ b/src/ast.h @@ -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 m_lhs; @@ -117,6 +121,7 @@ namespace AST { ) override; }; + /// @brief Same as fn()/// @brief class FunctionCallExpression : public Expression { private: std::unique_ptr m_fn_expr; @@ -140,6 +145,7 @@ namespace AST { ) override; }; + /// @brief Same as (type) value class CastExpression : public Expression { private: std::shared_ptr m_ty; @@ -163,6 +169,48 @@ namespace AST { ) override; }; + /// @brief Same as &value + class RefExpression : public Expression { + private: + std::unique_ptr m_expr; + public: + RefExpression( + token::Metadata meta, + std::unique_ptr 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 typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; + }; + + /// @brief Same as *value + class DerefExpression : public Expression { + private: + std::unique_ptr m_expr; + public: + DerefExpression( + token::Metadata meta, + std::unique_ptr 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 typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; + }; + class ReturnStatement : public Statement { private: diff --git a/src/codegen.cpp b/src/codegen.cpp index ff6afd3..e4f3faa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -111,6 +111,27 @@ 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 ptr_ty = dynamic_cast(value.ty.get()); + auto loaded = ptr_ty->m_inner->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; diff --git a/src/typechecker.cpp b/src/typechecker.cpp index ab8ef1f..51c552b 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -253,6 +253,35 @@ namespace AST { } }; } + std::shared_ptr RefExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> + ) { + auto expr_ty = this->m_expr->typecheck(state, scope, {}); + return std::shared_ptr { + new types::PointerType{ expr_ty } + }; + } + + std::shared_ptr DerefExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> + ) { + 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 { + new types::FundamentalType{ types::FundamentalTypeKind::Void } + }; + } + auto ptr_ty = dynamic_cast(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) { diff --git a/test.c b/test.c index 42e26d0..07dac4b 100644 --- a/test.c +++ b/test.c @@ -9,6 +9,7 @@ int fibonacci(int n) { int main() { printf("10th fibonacci number is %d!", fibonacci(10)); char res = 0; - res = 15; + char* test = &res; + *test = 15; return res; } \ No newline at end of file