Implement arrays
This commit is contained in:
parent
c0a2c41c33
commit
26779414a7
@ -61,6 +61,13 @@ namespace AST {
|
|||||||
return out.str();
|
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::string ExpressionStatement::formatted() {
|
||||||
std::stringstream out{ "" };
|
std::stringstream out{ "" };
|
||||||
out << this->m_expr->formatted();
|
out << this->m_expr->formatted();
|
||||||
|
|||||||
24
src/ast.h
24
src/ast.h
@ -211,6 +211,30 @@ namespace AST {
|
|||||||
) override;
|
) 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 {
|
class ReturnStatement : public Statement {
|
||||||
private:
|
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) {
|
void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) {
|
||||||
if (!builder.block)
|
if (!builder.block)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -162,6 +162,8 @@ std::optional<CompileOutput> compile(std::string_view in_filename) {
|
|||||||
builder.mod->print(llvm_ir_dest, nullptr);
|
builder.mod->print(llvm_ir_dest, nullptr);
|
||||||
llvm_ir_dest.flush();
|
llvm_ir_dest.flush();
|
||||||
|
|
||||||
|
std::cout << llvm_ir_string << std::endl;
|
||||||
|
|
||||||
// Print output to obj-file
|
// Print output to obj-file
|
||||||
std::error_code EC;
|
std::error_code EC;
|
||||||
std::string obj_string;
|
std::string obj_string;
|
||||||
|
|||||||
@ -160,22 +160,29 @@ namespace parsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto plain_expr = parse_plain_expression(inner);
|
auto plain_expr = parse_plain_expression(inner);
|
||||||
while (inner.peek().content == "(") {
|
while (inner.peek().content == "(" || inner.peek().content == "[") {
|
||||||
inner.next();
|
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;
|
int counter = 0;
|
||||||
while (inner.peek().content != ")") {
|
while (inner.peek().content != ")") {
|
||||||
if (counter++ > 0)
|
if (counter++ > 0)
|
||||||
inner.expect(token::Type::Symbol, ",");
|
inner.expect(token::Type::Symbol, ",");
|
||||||
args.push_back(parse_expression(inner).unwrap());
|
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;
|
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) {
|
void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
|
||||||
auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);
|
auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user