aboutsummaryrefslogtreecommitdiff
path: root/src/compile/tables.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 15:56:38 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 15:56:38 -0400
commite920d306fb51c16fd473033b64aa5ba5c3e07409 (patch)
treeab0a7cb47ad050f278981be1e0a4edc19b8daaee /src/compile/tables.c
parentc62c3200c7078f58b218def14c54bbfd26677069 (diff)
Split into more files: promotion, sets, tables, pointers, functions.
Diffstat (limited to 'src/compile/tables.c')
-rw-r--r--src/compile/tables.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/compile/tables.c b/src/compile/tables.c
new file mode 100644
index 00000000..0ddd310c
--- /dev/null
+++ b/src/compile/tables.c
@@ -0,0 +1,76 @@
+
+#include "../ast.h"
+#include "../compile.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+#include "../stdlib/text.h"
+#include "../types.h"
+#include "promotion.h"
+
+static ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject) {
+ DeclareMatch(e, entry, TableEntry);
+ return WrapAST(entry, MethodCall, .name = "set", .self = subject,
+ .args = new (arg_ast_t, .value = e->key, .next = new (arg_ast_t, .value = e->value)));
+}
+
+Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) {
+ DeclareMatch(table, ast, Table);
+ if (!table->entries) {
+ Text_t code = Text("((Table_t){");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), ")");
+ return Texts(code, "})");
+ }
+
+ type_t *key_t = Match(table_type, TableType)->key_type;
+ type_t *value_t = Match(table_type, TableType)->value_type;
+
+ if (value_t->tag == OptionalType)
+ code_err(ast, "Tables whose values are optional (", type_to_str(value_t), ") are not currently supported.");
+
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
+ if (entry->ast->tag == Comprehension) goto table_comprehension;
+ }
+
+ { // No comprehension:
+ env_t *key_scope = key_t->tag == EnumType ? with_enum_scope(env, key_t) : env;
+ env_t *value_scope = value_t->tag == EnumType ? with_enum_scope(env, value_t) : env;
+ Text_t code = Texts("Table(", compile_type(key_t), ", ", compile_type(value_t), ", ", compile_type_info(key_t),
+ ", ", compile_type_info(value_t));
+ if (table->fallback) code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")");
+ else code = Texts(code, ", /*fallback:*/ NULL");
+
+ size_t n = 0;
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next)
+ ++n;
+ code = Texts(code, ", ", String((int64_t)n));
+
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
+ DeclareMatch(e, entry->ast, TableEntry);
+ code = Texts(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ",
+ compile_to_type(value_scope, e->value, value_t), "}");
+ }
+ return Texts(code, ")");
+ }
+
+table_comprehension: {
+ static int64_t comp_num = 1;
+ env_t *scope = fresh_scope(env);
+ const char *comprehension_name = String("table$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = table_type, .is_stack = true));
+
+ Text_t code = Texts("({ Table_t ", comprehension_name, " = {");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), ");
+
+ code = Texts(code, "};");
+
+ Closure_t comp_action = {.fn = add_to_table_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
+ if (entry->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, entry->ast));
+ else code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var)));
+ }
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
+}