Add FieldAccessExpression
This commit is contained in:
parent
9ed753a238
commit
a12cf52c48
@ -68,6 +68,13 @@ namespace AST {
|
|||||||
return out.str();
|
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::string ListInitializerExpression::formatted() {
|
||||||
std::stringstream out{ "" };
|
std::stringstream out{ "" };
|
||||||
out << "{ ";
|
out << "{ ";
|
||||||
|
|||||||
26
src/ast.h
26
src/ast.h
@ -245,6 +245,32 @@ namespace AST {
|
|||||||
) override;
|
) 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 {
|
class ListInitializerExpression : public Expression {
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<Expression>> m_expressions;
|
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&) {
|
std::shared_ptr<types::Type> ListInitializerExpression::get_codegen_type(codegen::Scope&) {
|
||||||
return this->m_ty;
|
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(
|
std::shared_ptr<types::Type> ListInitializerExpression::typecheck(
|
||||||
typecheck::State& state,
|
typecheck::State& state,
|
||||||
typecheck::Scope& scope,
|
typecheck::Scope& scope,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user