From 02a33f3dd65ff7be262116edb4a37b3e0a74ac57 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 24 Aug 2025 18:27:05 -0400 Subject: Move field access to its own file --- src/compile/expressions.c | 82 ++---------------------------------------- src/compile/fieldaccess.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++ src/compile/fieldaccess.h | 8 +++++ 3 files changed, 101 insertions(+), 80 deletions(-) create mode 100644 src/compile/fieldaccess.c create mode 100644 src/compile/fieldaccess.h diff --git a/src/compile/expressions.c b/src/compile/expressions.c index a6bcff75..ce22042f 100644 --- a/src/compile/expressions.c +++ b/src/compile/expressions.c @@ -4,7 +4,6 @@ #include "../ast.h" #include "../config.h" #include "../environment.h" -#include "../stdlib/tables.h" #include "../stdlib/text.h" #include "../stdlib/util.h" #include "../typecheck.h" @@ -14,6 +13,7 @@ #include "conditionals.h" #include "declarations.h" #include "enums.h" +#include "fieldaccess.h" #include "functions.h" #include "indexing.h" #include "integers.h" @@ -254,85 +254,7 @@ Text_t compile(env_t *env, ast_t *ast) { case When: return compile_when_statement(env, ast); case If: return compile_if_expression(env, ast); case Reduction: return compile_reduction(env, ast); - case FieldAccess: { - DeclareMatch(f, ast, FieldAccess); - type_t *fielded_t = get_type(env, f->fielded); - type_t *value_t = value_type(fielded_t); - switch (value_t->tag) { - case TypeInfoType: { - DeclareMatch(info, value_t, TypeInfoType); - if (f->field[0] == '_') { - if (!type_eq(env->current_type, info->type)) - code_err(ast, "Fields that start with underscores are not " - "accessible " - "on types outside of the type definition."); - } - binding_t *b = get_binding(info->env, f->field); - if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type"); - if (b->code.length == 0) code_err(ast, "I couldn't figure out how to compile this field"); - return b->code; - } - case TextType: { - const char *lang = Match(value_t, TextType)->lang; - if (lang && streq(f->field, "text")) { - Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false); - return Texts("((Text_t)", text, ")"); - } else if (streq(f->field, "length")) { - return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); - } - code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values"); - } - case StructType: { - return compile_struct_field_access(env, ast); - } - case EnumType: { - return compile_enum_field_access(env, ast); - } - case ListType: { - if (streq(f->field, "length")) - return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); - code_err(ast, "There is no ", f->field, " field on lists"); - } - case SetType: { - if (streq(f->field, "items")) - return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); - else if (streq(f->field, "length")) - return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), - ").entries.length)"); - code_err(ast, "There is no '", f->field, "' field on sets"); - } - case TableType: { - if (streq(f->field, "length")) { - return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), - ").entries.length)"); - } else if (streq(f->field, "keys")) { - return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); - } else if (streq(f->field, "values")) { - DeclareMatch(table, value_t, TableType); - Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ", - compile_declaration(table->value_type, Text("v")), "; }, v)"); - return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), - ").entries;\n" - "LIST_INCREF(*entries);\n" - "List_t values = *entries;\n" - "values.data += ", - offset, - ";\n" - "values; })"); - } else if (streq(f->field, "fallback")) { - return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), - ").fallback; _fallback ? *_fallback : NONE_TABLE; })"); - } - code_err(ast, "There is no '", f->field, "' field on tables"); - } - case ModuleType: { - const char *name = Match(value_t, ModuleType)->name; - env_t *module_env = Table$str_get(*env->imports, name); - return compile(module_env, WrapAST(ast, Var, f->field)); - } - default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values"); - } - } + case FieldAccess: return compile_field_access(env, ast); case Index: return compile_indexing(env, ast); case InlineCCode: { type_t *t = get_type(env, ast); diff --git a/src/compile/fieldaccess.c b/src/compile/fieldaccess.c new file mode 100644 index 00000000..93b31665 --- /dev/null +++ b/src/compile/fieldaccess.c @@ -0,0 +1,91 @@ +// This file defines how to compile field accessing like `foo.x` +#include "../ast.h" +#include "../config.h" +#include "../environment.h" +#include "../stdlib/tables.h" +#include "../stdlib/text.h" +#include "../stdlib/util.h" +#include "../typecheck.h" +#include "declarations.h" +#include "enums.h" +#include "expressions.h" +#include "pointers.h" +#include "structs.h" + +Text_t compile_field_access(env_t *env, ast_t *ast) { + DeclareMatch(f, ast, FieldAccess); + type_t *fielded_t = get_type(env, f->fielded); + type_t *value_t = value_type(fielded_t); + switch (value_t->tag) { + case TypeInfoType: { + DeclareMatch(info, value_t, TypeInfoType); + if (f->field[0] == '_') { + if (!type_eq(env->current_type, info->type)) + code_err(ast, "Fields that start with underscores are not " + "accessible " + "on types outside of the type definition."); + } + binding_t *b = get_binding(info->env, f->field); + if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type"); + if (b->code.length == 0) code_err(ast, "I couldn't figure out how to compile this field"); + return b->code; + } + case TextType: { + const char *lang = Match(value_t, TextType)->lang; + if (lang && streq(f->field, "text")) { + Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false); + return Texts("((Text_t)", text, ")"); + } else if (streq(f->field, "length")) { + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + } + code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values"); + } + case StructType: { + return compile_struct_field_access(env, ast); + } + case EnumType: { + return compile_enum_field_access(env, ast); + } + case ListType: { + if (streq(f->field, "length")) + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + code_err(ast, "There is no ", f->field, " field on lists"); + } + case SetType: { + if (streq(f->field, "items")) + return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); + else if (streq(f->field, "length")) + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + code_err(ast, "There is no '", f->field, "' field on sets"); + } + case TableType: { + if (streq(f->field, "length")) { + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + } else if (streq(f->field, "keys")) { + return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); + } else if (streq(f->field, "values")) { + DeclareMatch(table, value_t, TableType); + Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ", + compile_declaration(table->value_type, Text("v")), "; }, v)"); + return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), + ").entries;\n" + "LIST_INCREF(*entries);\n" + "List_t values = *entries;\n" + "values.data += ", + offset, + ";\n" + "values; })"); + } else if (streq(f->field, "fallback")) { + return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), + ").fallback; _fallback ? *_fallback : NONE_TABLE; })"); + } + code_err(ast, "There is no '", f->field, "' field on tables"); + } + case ModuleType: { + const char *name = Match(value_t, ModuleType)->name; + env_t *module_env = Table$str_get(*env->imports, name); + return compile(module_env, WrapAST(ast, Var, f->field)); + } + default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values"); + } +} diff --git a/src/compile/fieldaccess.h b/src/compile/fieldaccess.h new file mode 100644 index 00000000..849df080 --- /dev/null +++ b/src/compile/fieldaccess.h @@ -0,0 +1,8 @@ +// This file defines how to compile field accessing like `foo.x` +#pragma once + +#include "../ast.h" +#include "../environment.h" +#include "../stdlib/datatypes.h" + +Text_t compile_field_access(env_t *env, ast_t *ast); -- cgit v1.2.3