Add FieldAccessExpression
This commit is contained in:
parent
9ed753a238
commit
a12cf52c48
@ -68,6 +68,13 @@ namespace AST {
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string FieldAccessExpression::formatted() {
|
||||
std::stringstream out{ "" };
|
||||
out << this->m_expr->formatted();
|
||||
out << "." << this->m_field;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string ListInitializerExpression::formatted() {
|
||||
std::stringstream out{ "" };
|
||||
out << "{ ";
|
||||
|
||||
26
src/ast.h
26
src/ast.h
@ -245,6 +245,32 @@ namespace AST {
|
||||
) override;
|
||||
};
|
||||
|
||||
/// @brief Same as value.field
|
||||
class FieldAccessExpression : public Expression {
|
||||
private:
|
||||
std::unique_ptr<Expression> m_expr;
|
||||
std::string m_field;
|
||||
public:
|
||||
FieldAccessExpression(
|
||||
token::Metadata meta,
|
||||
std::unique_ptr<Expression> expr,
|
||||
std::string field)
|
||||
: Expression{ meta }
|
||||
, m_expr{ std::move(expr) }
|
||||
, m_field{ field } {
|
||||
}
|
||||
virtual ~FieldAccessExpression() override = default;
|
||||
virtual std::string formatted() override;
|
||||
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
|
||||
virtual std::shared_ptr<types::Type> get_codegen_type(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;
|
||||
};
|
||||
|
||||
/// @brief Same as {value1, value2}
|
||||
class ListInitializerExpression : public Expression {
|
||||
private:
|
||||
std::vector<std::unique_ptr<Expression>> m_expressions;
|
||||
|
||||
@ -323,6 +323,72 @@ namespace AST {
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<types::Type> FieldAccessExpression::get_codegen_type(codegen::Scope& scope) {
|
||||
auto ty = this->m_expr->get_codegen_type(scope);
|
||||
if (ty->m_kind == types::TypeKind::Struct) {
|
||||
auto struct_ty = dynamic_cast<types::StructType*>(ty.get());
|
||||
if (struct_ty->m_fields) {
|
||||
for (auto& field : *struct_ty->m_fields) {
|
||||
if (field.first == this->m_field)
|
||||
return field.second;
|
||||
}
|
||||
throw CompileError("Unknown field", this->m_meta);
|
||||
}
|
||||
throw CompileError("Cannot access a field of opaque struct", this->m_meta);
|
||||
}
|
||||
else {
|
||||
throw CompileError("Tried accessing a non-struct", this->m_meta);
|
||||
}
|
||||
}
|
||||
|
||||
codegen::StackValue FieldAccessExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) {
|
||||
auto lvalued = scope.with_lvalue();
|
||||
auto struct_ptr = this->m_expr->codegen(builder, lvalued);
|
||||
if (struct_ptr.ty->m_kind == types::TypeKind::Pointer) {
|
||||
auto ptr_ty = dynamic_cast<types::PointerType*>(struct_ptr.ty.get());
|
||||
if (ptr_ty->m_inner->m_kind == types::TypeKind::Struct) {
|
||||
auto struct_ty = dynamic_cast<types::StructType*>(ptr_ty->m_inner.get());
|
||||
|
||||
int idx = -1;
|
||||
auto field_ty = std::shared_ptr<types::Type>{};
|
||||
|
||||
for (int i = 0; i < static_cast<int>(struct_ty->m_fields->size()); i++) {
|
||||
auto field = (*struct_ty->m_fields)[i];
|
||||
if (field.first == this->m_field) {
|
||||
idx = i;
|
||||
field_ty = field.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto gep = builder.builder->CreateStructGEP(
|
||||
ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx);
|
||||
|
||||
auto ptr_ty = std::shared_ptr<types::Type>{
|
||||
new types::PointerType { field_ty }
|
||||
};
|
||||
|
||||
if (scope.is_lvalue) {
|
||||
return codegen::StackValue{
|
||||
gep,
|
||||
ptr_ty
|
||||
};
|
||||
}
|
||||
else {
|
||||
auto loaded = ptr_ty->load(builder, gep, scope.structs);
|
||||
return codegen::StackValue{ loaded.first, loaded.second };
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw CompileError("Tried field-accessing a non-struct-pointer", this->m_meta);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw CompileError("Tried field-accessing a non-pointer", this->m_meta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<types::Type> ListInitializerExpression::get_codegen_type(codegen::Scope&) {
|
||||
return this->m_ty;
|
||||
|
||||
@ -309,6 +309,39 @@ namespace AST {
|
||||
};
|
||||
}
|
||||
|
||||
std::shared_ptr<types::Type> FieldAccessExpression::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::Struct) {
|
||||
state.errors.push_back(
|
||||
CompileError("Tried to access " + expr_ty->formatted() + "." + this->m_field, this->m_meta));
|
||||
return std::shared_ptr<types::Type> {
|
||||
new types::FundamentalType{ types::FundamentalTypeKind::Void }
|
||||
};
|
||||
}
|
||||
|
||||
auto struct_ty = dynamic_cast<types::StructType*>(expr_ty.get());
|
||||
if (struct_ty->m_fields) {
|
||||
for (auto& field : *struct_ty->m_fields) {
|
||||
if (field.first == this->m_field) {
|
||||
return field.second;
|
||||
}
|
||||
}
|
||||
state.errors.push_back(CompileError("No such field", this->m_meta));
|
||||
return std::shared_ptr<types::Type> {
|
||||
new types::FundamentalType{ types::FundamentalTypeKind::Void }
|
||||
};
|
||||
}
|
||||
|
||||
state.errors.push_back(CompileError("Cannot access fields of opaque struct", this->m_meta));
|
||||
return std::shared_ptr<types::Type> {
|
||||
new types::FundamentalType{ types::FundamentalTypeKind::Void }
|
||||
};
|
||||
}
|
||||
|
||||
std::shared_ptr<types::Type> ListInitializerExpression::typecheck(
|
||||
typecheck::State& state,
|
||||
typecheck::Scope& scope,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user