Implement arrays

This commit is contained in:
Sofia 2026-04-14 15:55:13 +03:00
parent c0a2c41c33
commit 26779414a7
7 changed files with 139 additions and 16 deletions

View File

@ -61,6 +61,13 @@ namespace AST {
return out.str();
}
std::string IndexAccessExpression::formatted() {
std::stringstream out{ "" };
out << this->m_expr->formatted();
out << "[" << this->m_num << "]";
return out.str();
}
std::string ExpressionStatement::formatted() {
std::stringstream out{ "" };
out << this->m_expr->formatted();

View File

@ -211,6 +211,30 @@ namespace AST {
) override;
};
/// @brief Same as value[num]
class IndexAccessExpression : public Expression {
private:
std::unique_ptr<Expression> m_expr;
uint32_t m_num;
public:
IndexAccessExpression(
token::Metadata meta,
std::unique_ptr<Expression> expr,
uint32_t num)
: Expression{ meta }
, m_expr{ std::move(expr) }
, m_num{ num } {
}
virtual ~IndexAccessExpression() 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

@ -131,6 +131,60 @@ namespace AST {
}
codegen::StackValue IndexAccessExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) {
auto lvalue_scope = scope.with_lvalue();
auto value = this->m_expr->codegen(builder, lvalue_scope);
std::shared_ptr<types::Type> inner_ty{};
std::vector<llvm::Value*> idx_list{ };
idx_list.push_back(llvm::ConstantInt::get(builder.builder->getInt32Ty(), this->m_num));
if (value.ty->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(value.ty.get());
if (ptr_ty->m_inner->m_kind == types::TypeKind::Pointer) {
auto inner_ptr_ty = dynamic_cast<types::PointerType*>(ptr_ty->m_inner.get());
auto gep_value = builder.builder->CreateGEP(inner_ptr_ty->m_inner->codegen(builder), value.value, idx_list, "GEP");
if (scope.is_lvalue) {
return codegen::StackValue{
gep_value,
value.ty,
};
}
else {
auto loaded = value.ty->load(builder, gep_value);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
}
// Must be an array otherwise
auto arr_ty = dynamic_cast<types::ArrayType*>(ptr_ty->m_inner.get());
std::cout << arr_ty->m_inner->formatted() << std::endl;
auto gep_value = builder.builder->CreateGEP(arr_ty->m_inner->codegen(builder), value.value, idx_list, "GEP");
if (scope.is_lvalue) {
return codegen::StackValue{
gep_value,
value.ty,
};
}
else {
auto inner_ptr_ty = types::PointerType{ arr_ty->m_inner };
auto loaded = inner_ptr_ty.load(builder, gep_value);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
}
throw CompileError("Tried indexing a non-pointer", this->m_meta);
}
void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) {
if (!builder.block)
return;

View File

@ -162,6 +162,8 @@ std::optional<CompileOutput> compile(std::string_view in_filename) {
builder.mod->print(llvm_ir_dest, nullptr);
llvm_ir_dest.flush();
std::cout << llvm_ir_string << std::endl;
// Print output to obj-file
std::error_code EC;
std::string obj_string;

View File

@ -160,22 +160,29 @@ namespace parsing {
}
auto plain_expr = parse_plain_expression(inner);
while (inner.peek().content == "(") {
inner.next();
while (inner.peek().content == "(" || inner.peek().content == "[") {
if (inner.peek().content == "(") {
inner.next();
std::vector<std::unique_ptr<AST::Expression>> args{};
std::vector<std::unique_ptr<AST::Expression>> args{};
int counter = 0;
while (inner.peek().content != ")") {
if (counter++ > 0)
inner.expect(token::Type::Symbol, ",");
args.push_back(parse_expression(inner).unwrap());
int counter = 0;
while (inner.peek().content != ")") {
if (counter++ > 0)
inner.expect(token::Type::Symbol, ",");
args.push_back(parse_expression(inner).unwrap());
}
inner.expect(token::Type::Symbol, ")");
auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) };
plain_expr = std::unique_ptr<AST::Expression>{ fn_call };
}
else if (auto postfix = parse_array_postfix(inner, false); postfix.ok()) {
auto idx_expr = new AST::IndexAccessExpression{
before_meta + inner.metadata(), plain_expr.unwrap(), *postfix.unwrap() };
plain_expr = std::unique_ptr<AST::Expression>{ idx_expr };
}
inner.expect(token::Type::Symbol, ")");
auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) };
plain_expr = std::unique_ptr<AST::Expression>{ fn_call };
}

View File

@ -281,6 +281,34 @@ namespace AST {
return ptr_ty->m_inner;
}
std::shared_ptr<types::Type> IndexAccessExpression::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 && expr_ty->m_kind != types::TypeKind::Array) {
state.errors.push_back(
CompileError("Tried to index " + expr_ty->formatted(), this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
}
if (expr_ty->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return ptr_ty->m_inner;
}
else if (expr_ty->m_kind == types::TypeKind::Array) {
auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.get());
return ptr_ty->m_inner;
}
// Default return type
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
}
void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);

7
test.c
View File

@ -15,7 +15,8 @@ int main() {
char somelist[5];
char res = 10;
modify_value(&res);
return res;
somelist[0] = 15;
somelist[1] = 20;
return somelist[0];
}