#include "typechecker.h" #include "ast.h" #include "errors.h" namespace AST { std::shared_ptr IntLiteralExpression::typecheck( typecheck::State&, typecheck::Scope&, std::optional> ) { return std::shared_ptr{ new types::FundamentalType{ types::FundamentalTypeKind::Int } }; } std::shared_ptr StringLiteralExpression::typecheck( typecheck::State&, typecheck::Scope&, std::optional> ) { auto char_ty = std::shared_ptr{ new types::FundamentalType{ types::FundamentalTypeKind::Char } }; auto ptr_ty = new types::PointerType{ char_ty }; return std::shared_ptr{ptr_ty}; } std::shared_ptr ValueReferenceExpression::typecheck( typecheck::State&, typecheck::Scope& scope, std::optional> ) { return scope.symbols[this->m_name]; } std::shared_ptr BinaryOperationExpression::typecheck( typecheck::State& state, typecheck::Scope& scope, std::optional> ) { auto lhs_ty = this->m_lhs->typecheck(state, scope, {}); auto rhs_ty = this->m_rhs->typecheck(state, scope, {}); // TODO actually check binop types properly return lhs_ty; } std::shared_ptr FunctionCallExpression::typecheck( typecheck::State& state, typecheck::Scope& scope, std::optional> ) { auto expr_ty = this->m_fn_expr->typecheck(state, scope, {}); // TODO make sure function_ty really is a function type auto fn_ty = dynamic_cast(expr_ty.get()); if (this->m_args.size() < fn_ty->m_param_tys.size()) { state.errors.push_back(CompileError("too few arguments", this->m_meta)); } else if (this->m_args.size() > fn_ty->m_param_tys.size() && !fn_ty->m_vararg) { state.errors.push_back(CompileError("too many arguments", this->m_meta)); } else { for (int i = 0; i < static_cast(fn_ty->m_param_tys.size()); i++) { auto expected_param_ty = fn_ty->m_param_tys[i]; auto param_ty = this->m_args[i]->typecheck(state, scope, expected_param_ty); // TODO make sure types actually match } } return fn_ty->m_ret_ty; } void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { this->m_expr->typecheck(state, scope, scope.return_ty); } void InitializationStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { if (this->m_expr) { (*this->m_expr)->typecheck(state, scope, this->m_type); } scope.symbols[this->m_name] = this->m_type; } void ExpressionStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { this->m_expr->typecheck(state, scope, {}); } void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { auto bool_ty_ptr = new types::FundamentalType{ types::FundamentalTypeKind::Bool }; this->m_condition->typecheck(state, scope, std::shared_ptr{ bool_ty_ptr }); this->m_then->typecheck(state, scope); if (this->m_else) { (*this->m_else)->typecheck(state, scope); } } void Function::typecheck(typecheck::State& state, typecheck::Scope& scope) { auto return_ty = this->m_return_ty; std::vector> param_tys{}; for (auto& param : this->m_params) { param_tys.push_back(param.second); } auto function_ty = new types::FunctionType{ return_ty, param_tys, this->m_is_vararg }; scope.symbols[this->m_name] = std::shared_ptr{ function_ty }; typecheck::Scope inner{ scope }; if (this->m_statements) { for (auto& statement : *this->m_statements) { statement->typecheck(state, inner); } } } }