Implement arrays
This commit is contained in:
parent
c0a2c41c33
commit
26779414a7
@ -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();
|
||||
|
||||
24
src/ast.h
24
src/ast.h
@ -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:
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 };
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user