From e45f120f1cfbe233bbaa814326932ac3669fe8a4 Mon Sep 17 00:00:00 2001 From: Sofia Date: Mon, 13 Apr 2026 00:35:14 +0300 Subject: [PATCH] Add typecheck-functions to AST --- CMakeLists.txt | 10 ++++++- src/ast.h | 46 ++++++++++++++++++++++++++++--- src/typechecker.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++ src/typechecker.h | 12 ++++++++- 4 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 src/typechecker.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ac7ab72..6e5e532 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,15 @@ separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS_LIST}) # Executable -add_executable(${PROJECT_NAME} src/main.cpp src/tokens.cpp src/parsing.cpp src/ast.cpp src/codegen.cpp src/types.cpp) +add_executable(${PROJECT_NAME} + src/main.cpp + src/tokens.cpp + src/parsing.cpp + src/ast.cpp + src/codegen.cpp + src/types.cpp + src/typechecker.cpp +) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Weffc++ -Wextra -Wpedantic -Werror) diff --git a/src/ast.h b/src/ast.h index d0fb707..048010f 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1,14 +1,15 @@ #ifndef AST_H #define AST_H -#include "codegen.h" -#include "types.h" -#include "tokens.h" - #include #include #include +#include "codegen.h" +#include "types.h" +#include "tokens.h" +#include "typechecker.h" + namespace AST { class Node { public: @@ -23,12 +24,18 @@ namespace AST { public: Expression(token::Metadata meta) : Node{ meta } {} virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) = 0; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) = 0; }; class Statement : public Node { public: Statement(token::Metadata meta) : Node{ meta } {} virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) = 0; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) = 0; }; class IntLiteralExpression : public Expression { @@ -39,6 +46,11 @@ namespace AST { virtual ~IntLiteralExpression() override = default; virtual std::string formatted() override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; }; class StringLiteralExpression : public Expression { @@ -49,6 +61,11 @@ namespace AST { virtual ~StringLiteralExpression() override = default; virtual std::string formatted() override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; }; class ValueReferenceExpression : public Expression { @@ -59,6 +76,11 @@ namespace AST { virtual ~ValueReferenceExpression() override = default; virtual std::string formatted() override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; }; class BinaryOperationExpression : public Expression { @@ -80,6 +102,11 @@ namespace AST { virtual ~BinaryOperationExpression() override = default; virtual std::string formatted() override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; }; class FunctionCallExpression : public Expression { @@ -98,6 +125,11 @@ namespace AST { virtual ~FunctionCallExpression() override = default; virtual std::string formatted() override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual typecheck::TypecheckResult typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; }; @@ -111,6 +143,7 @@ namespace AST { virtual ~ReturnStatement() override = default; virtual std::string formatted() override; virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; class InitializationStatement : public Statement { @@ -132,6 +165,7 @@ namespace AST { virtual ~InitializationStatement() override = default; virtual std::string formatted() override; virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; class ExpressionStatement : public Statement { @@ -144,6 +178,7 @@ namespace AST { virtual ~ExpressionStatement() override = default; virtual std::string formatted() override; virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; class IfStatement : public Statement { @@ -164,12 +199,14 @@ namespace AST { virtual ~IfStatement() override = default; virtual std::string formatted() override; virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; class TopLevelStatement : public Node { public: TopLevelStatement(token::Metadata meta) : Node{ meta } {} virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) = 0; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) = 0; }; class Function : public TopLevelStatement { @@ -197,6 +234,7 @@ namespace AST { virtual ~Function() override = default; virtual std::string formatted() override; virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; } diff --git a/src/typechecker.cpp b/src/typechecker.cpp new file mode 100644 index 0000000..c4aed66 --- /dev/null +++ b/src/typechecker.cpp @@ -0,0 +1,66 @@ + +#include "typechecker.h" +#include "ast.h" +#include "errors.h" + +namespace AST { + typecheck::TypecheckResult IntLiteralExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + throw CompileError("TODO", {}); + } + + typecheck::TypecheckResult StringLiteralExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + throw CompileError("TODO", {}); + } + + typecheck::TypecheckResult ValueReferenceExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + throw CompileError("TODO", {}); + } + + typecheck::TypecheckResult BinaryOperationExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + throw CompileError("TODO", {}); + } + + typecheck::TypecheckResult FunctionCallExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + throw CompileError("TODO", {}); + } + + void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { + throw CompileError("TODO", {}); + } + + void InitializationStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { + throw CompileError("TODO", {}); + } + + void ExpressionStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { + throw CompileError("TODO", {}); + } + + void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { + throw CompileError("TODO", {}); + } + + void Function::typecheck(typecheck::State& state, typecheck::Scope& scope) { + throw CompileError("TODO", {}); + } +} \ No newline at end of file diff --git a/src/typechecker.h b/src/typechecker.h index 5319f25..a32e230 100644 --- a/src/typechecker.h +++ b/src/typechecker.h @@ -4,14 +4,24 @@ #include #include "types.h" +#include "errors.h" namespace typecheck { + enum class TypecheckResult { + /// @brief The types match perfectly (enough) + Suitable, + /// @brief The original type can be implicitly cast into the given type + Castable, + /// @brief The types are totally incompatible + Error, + }; + struct Scope { std::map symbols; }; struct State { - + std::vector errors; }; }