aboutsummaryrefslogtreecommitdiff
path: root/src/compile.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 16:35:01 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 16:35:01 -0400
commite4d080f598b8528d5200deccde279ff02ac5750e (patch)
treef3a82306e82b1d8453a3c8d02fe7a06c0e355669 /src/compile.c
parent5e82b074667627d1e6f44247396bae80f1c02fff (diff)
Move method calls into separate files
Diffstat (limited to 'src/compile.c')
-rw-r--r--src/compile.c334
1 files changed, 4 insertions, 330 deletions
diff --git a/src/compile.c b/src/compile.c
index fa47e63c..3f7585fd 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1964,11 +1964,7 @@ Text_t compile(env_t *env, ast_t *ast) {
compile(env, call->self), "}, ", compile_type_info(self_t), ")");
}
- int64_t pointer_depth = 0;
- type_t *self_value_t = self_t;
- for (; self_value_t->tag == PointerType; self_value_t = Match(self_value_t, PointerType)->pointed)
- pointer_depth += 1;
-
+ type_t *self_value_t = value_type(self_t);
if (self_value_t->tag == TypeInfoType || self_value_t->tag == ModuleType) {
return compile(env,
WrapAST(ast, FunctionCall,
@@ -1984,331 +1980,10 @@ Text_t compile(env_t *env, ast_t *ast) {
.fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
.args = call->args));
- Text_t self = compile(env, call->self);
-
-#define EXPECT_POINTER(article, name) \
- do { \
- if (pointer_depth < 1) \
- code_err(call->self, "I expected " article " " name " pointer here, not " article " " name " value"); \
- else if (pointer_depth > 1) \
- code_err(call->self, "I expected " article " " name " pointer here, not a nested " name " pointer"); \
- } while (0)
switch (self_value_t->tag) {
- case ListType: {
- type_t *item_t = Match(self_value_t, ListType)->item_type;
- Text_t padded_item_size = Texts("sizeof(", compile_type(item_t), ")");
-
- if (streq(call->name, "insert")) {
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec =
- new (arg_t, .name = "item", .type = item_t,
- .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
- return Texts("List$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "insert_all")) {
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec =
- new (arg_t, .name = "items", .type = self_value_t,
- .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
- return Texts("List$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "remove_at")) {
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new (
- arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "-1"),
- .next = new (arg_t, .name = "count", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "1")));
- return Texts("List$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "remove_item")) {
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
- .next = new (arg_t, .name = "max_count", .type = INT_TYPE,
- .default_val = FakeAST(Int, .str = "-1")));
- return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "has")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
- return Texts("List$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "sample")) {
- type_t *random_num_type = parse_type_string(env, "func(->Num)?");
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec =
- new (arg_t, .name = "count", .type = INT_TYPE,
- .next = new (arg_t, .name = "weights",
- .type = Type(ListType, .item_type = Type(NumType, .bits = TYPE_NBITS64)),
- .default_val = FakeAST(None),
- .next = new (arg_t, .name = "random", .type = random_num_type,
- .default_val = FakeAST(None))));
- return Texts("List$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "shuffle")) {
- type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec =
- new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
- return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "shuffled")) {
- type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec =
- new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
- return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "random")) {
- type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec =
- new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
- return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type(item_t), ")");
- } else if (streq(call->name, "sort") || streq(call->name, "sorted")) {
- if (streq(call->name, "sort")) EXPECT_POINTER("a", "list");
- else self = compile_to_pointer_depth(env, call->self, 0, false);
- Text_t comparison;
- if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
- {.name = "y", .type = item_ptr});
- arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
- comparison = compile_arguments(env, ast, arg_spec, call->args);
- } else {
- comparison = Texts("((Closure_t){.fn=generic_compare, "
- ".userdata=(void*)",
- compile_type_info(item_t), "})");
- }
- return Texts("List$", call->name, "(", self, ", ", comparison, ", ", padded_item_size, ")");
- } else if (streq(call->name, "heapify")) {
- EXPECT_POINTER("a", "list");
- Text_t comparison;
- if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
- {.name = "y", .type = item_ptr});
- arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
- comparison = compile_arguments(env, ast, arg_spec, call->args);
- } else {
- comparison = Texts("((Closure_t){.fn=generic_compare, "
- ".userdata=(void*)",
- compile_type_info(item_t), "})");
- }
- return Texts("List$heapify(", self, ", ", comparison, ", ", padded_item_size, ")");
- } else if (streq(call->name, "heap_push")) {
- EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
- {.name = "y", .type = item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
- ".userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type = Type(ClosureType, .fn = fn_t));
- arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
- .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
- .default_val = default_cmp));
- Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
- return Texts("List$heap_push_value(", self, ", ", arg_code, ", ", padded_item_size, ")");
- } else if (streq(call->name, "heap_pop")) {
- EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
- {.name = "y", .type = item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
- ".userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type = Type(ClosureType, .fn = fn_t));
- arg_t *arg_spec =
- new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t), .default_val = default_cmp);
- Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
- return Texts("List$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ",
- promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
- } else if (streq(call->name, "binary_search")) {
- self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
- {.name = "y", .type = item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
- ".userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type = Type(ClosureType, .fn = fn_t));
- arg_t *arg_spec = new (arg_t, .name = "target", .type = item_t,
- .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
- .default_val = default_cmp));
- Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
- return Texts("List$binary_search_value(", self, ", ", arg_code, ")");
- } else if (streq(call->name, "clear")) {
- EXPECT_POINTER("a", "list");
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("List$clear(", self, ")");
- } else if (streq(call->name, "find")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
- return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "where")) {
- self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
- type_t *predicate_type =
- Type(ClosureType, .fn = NewFunctionType(Type(BoolType), {.name = "item", .type = item_ptr}));
- arg_t *arg_spec = new (arg_t, .name = "predicate", .type = predicate_type);
- return Texts("List$first(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
- } else if (streq(call->name, "from")) {
- self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE);
- return Texts("List$from(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
- } else if (streq(call->name, "to")) {
- self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new (arg_t, .name = "last", .type = INT_TYPE);
- return Texts("List$to(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
- } else if (streq(call->name, "slice")) {
- self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE,
- .next = new (arg_t, .name = "last", .type = INT_TYPE));
- return Texts("List$slice(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
- } else if (streq(call->name, "by")) {
- self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new (arg_t, .name = "stride", .type = INT_TYPE);
- return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
- } else if (streq(call->name, "reversed")) {
- self = compile_to_pointer_depth(env, call->self, 0, true);
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("List$reversed(", self, ", ", padded_item_size, ")");
- } else if (streq(call->name, "unique")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("Table$from_entries(", self, ", Set$info(", compile_type_info(item_t), "))");
- } else if (streq(call->name, "pop")) {
- EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new (arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, "-1"));
- Text_t index = compile_arguments(env, ast, arg_spec, call->args);
- return Texts("List$pop(", self, ", ", index, ", ", compile_type(item_t), ", _, ",
- promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
- } else if (streq(call->name, "counts")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("List$counts(", self, ", ", compile_type_info(self_value_t), ")");
- } else code_err(ast, "There is no '", call->name, "' method for lists");
- }
- case SetType: {
- DeclareMatch(set, self_value_t, SetType);
- if (streq(call->name, "has")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "key", .type = set->item_type);
- return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "add")) {
- EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
- return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", NULL, ", compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "add_all")) {
- EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new (arg_t, .name = "items",
- .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
- return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$set(set, to_add.data + i*to_add.stride, NULL, ",
- compile_type_info(self_value_t), ");\n", "(void)0; })");
- } else if (streq(call->name, "remove")) {
- EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
- return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "remove_all")) {
- EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new (arg_t, .name = "items",
- .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
- return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$remove(set, to_add.data + i*to_add.stride, ",
- compile_type_info(self_value_t), ");\n", "(void)0; })");
- } else if (streq(call->name, "clear")) {
- EXPECT_POINTER("a", "set");
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("Table$clear(", self, ")");
- } else if (streq(call->name, "with")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
- return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "overlap")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
- return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "without")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
- return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "is_subset_of")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (
- arg_t, .name = "other", .type = self_value_t,
- .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
- return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "is_superset_of")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (
- arg_t, .name = "other", .type = self_value_t,
- .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
- return Texts("Table$is_superset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
- } else code_err(ast, "There is no '", call->name, "' method for tables");
- }
- case TableType: {
- DeclareMatch(table, self_value_t, TableType);
- if (streq(call->name, "get")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
- return Texts("Table$get_optional(", self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ",
- compile_none(table->value_type), ", ", compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "get_or_set")) {
- self = compile_to_pointer_depth(env, call->self, 1, false);
- arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
- .next = new (arg_t, .name = "default", .type = table->value_type,
- .default_val = table->default_value));
- return Texts("*Table$get_or_setdefault(", self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "has")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
- return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "set")) {
- EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
- .next = new (arg_t, .name = "value", .type = table->value_type));
- return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "remove")) {
- EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
- return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "clear")) {
- EXPECT_POINTER("a", "table");
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("Table$clear(", self, ")");
- } else if (streq(call->name, "sorted")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- (void)compile_arguments(env, ast, NULL, call->args);
- return Texts("Table$sorted(", self, ", ", compile_type_info(self_value_t), ")");
- } else if (streq(call->name, "with_fallback")) {
- self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new (arg_t, .name = "fallback", .type = Type(OptionalType, self_value_t));
- return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ")");
- } else code_err(ast, "There is no '", call->name, "' method for tables");
- }
+ case ListType: return compile_list_method_call(env, ast);
+ case SetType: return compile_set_method_call(env, ast);
+ case TableType: return compile_table_method_call(env, ast);
default: {
DeclareMatch(methodcall, ast, MethodCall);
type_t *fn_t = get_method_type(env, methodcall->self, methodcall->name);
@@ -2318,7 +1993,6 @@ Text_t compile(env_t *env, ast_t *ast) {
return Texts(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")");
}
}
-#undef EXPECT_POINTER
}
case FunctionCall: return compile_function_call(env, ast);
case Deserialize: {