aboutsummaryrefslogtreecommitdiff
path: root/src/compile/fieldaccess.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 18:27:05 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 18:27:05 -0400
commit02a33f3dd65ff7be262116edb4a37b3e0a74ac57 (patch)
treeecb0b666b3672c60be3288d5b7a9a0bac9852f65 /src/compile/fieldaccess.c
parent74e8aa30901dba029f3e39d187337a09740db4e0 (diff)
Move field access to its own file
Diffstat (limited to 'src/compile/fieldaccess.c')
-rw-r--r--src/compile/fieldaccess.c91
1 files changed, 91 insertions, 0 deletions
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");
+ }
+}