diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 15:29:52 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 15:29:52 -0400 |
| commit | 3f9f82ca53ed353d10ae65fc958e73193e8d9739 (patch) | |
| tree | cb92b570cd78a015cb62ae5c776d14cad7fe2b22 /src | |
| parent | 634d1ad756fca46e1e8aec93a265998232dd58a6 (diff) | |
Move more stuff into structs/enums files
Diffstat (limited to 'src')
| -rw-r--r-- | src/compile.c | 115 | ||||
| -rw-r--r-- | src/compile.h | 16 | ||||
| -rw-r--r-- | src/compile/enums.c | 38 | ||||
| -rw-r--r-- | src/compile/enums.h | 4 | ||||
| -rw-r--r-- | src/compile/pointer.c | 49 | ||||
| -rw-r--r-- | src/compile/pointer.h | 6 | ||||
| -rw-r--r-- | src/compile/structs.c | 56 | ||||
| -rw-r--r-- | src/compile/structs.h | 3 |
8 files changed, 172 insertions, 115 deletions
diff --git a/src/compile.c b/src/compile.c index a81b74d5..c2c931c8 100644 --- a/src/compile.c +++ b/src/compile.c @@ -10,6 +10,7 @@ #include "compile.h" #include "compile/enums.h" #include "compile/list.h" +#include "compile/pointer.h" #include "compile/structs.h" #include "config.h" #include "environment.h" @@ -25,16 +26,13 @@ typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *); -static Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref); static Text_t compile_text(env_t *env, ast_t *ast, Text_t color); static Text_t compile_text_literal(Text_t literal); -static Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); static Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t); static Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target); static Text_t compile_unsigned_type(type_t *t); static Text_t promote_to_optional(type_t *t, Text_t code); static Text_t compile_none(type_t *t); -static Text_t compile_empty(type_t *t); static Text_t compile_declared_value(env_t *env, ast_t *declaration_ast); static Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type); static Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type); @@ -2073,42 +2071,6 @@ Text_t compile_text(env_t *env, ast_t *ast, Text_t color) { return expr_as_text(expr, t, color); } -Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) { - Text_t val = compile(env, ast); - type_t *t = get_type(env, ast); - int64_t depth = 0; - for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed) - ++depth; - - // Passing a literal value won't trigger an incref, because it's ephemeral, - // e.g. [10, 20].reversed() - if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false; - - while (depth != target_depth) { - if (depth < target_depth) { - if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")"); - else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast))); - t = Type(PointerType, .pointed = t, .is_stack = true); - ++depth; - } else { - DeclareMatch(ptr, t, PointerType); - val = Texts("*(", val, ")"); - t = ptr->pointed; - --depth; - } - } - - while (t->tag == PointerType) { - DeclareMatch(ptr, t, PointerType); - t = ptr->pointed; - } - - if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")"); - else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")"); - - return val; -} - public Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) { assert(!is_incomplete_type(t)); @@ -2370,6 +2332,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { return EMPTY_TEXT; } +public Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) { Table_t used_args = {}; Text_t code = EMPTY_TEXT; @@ -2531,6 +2494,7 @@ Text_t compile_none(type_t *t) { return EMPTY_TEXT; } +public Text_t compile_empty(type_t *t) { if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type"); @@ -2567,30 +2531,8 @@ Text_t compile_empty(type_t *t) { case NumType: { return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)"); } - case StructType: { - DeclareMatch(struct_, t, StructType); - Text_t code = Texts("((", compile_type(t), "){"); - for (arg_t *field = struct_->fields; field; field = field->next) { - Text_t empty_field = - field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type); - if (empty_field.length == 0) return EMPTY_TEXT; - - code = Texts(code, empty_field); - if (field->next) code = Texts(code, ", "); - } - return Texts(code, "})"); - } - case EnumType: { - DeclareMatch(enum_, t, EnumType); - tag_t *tag = enum_->tags; - assert(tag); - assert(tag->type); - if (Match(tag->type, StructType)->fields) - return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", - compile_empty(tag->type), "})"); - else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})"); - else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")"); - } + case StructType: return compile_empty_struct(t); + case EnumType: return compile_empty_enum(t); default: return EMPTY_TEXT; } return EMPTY_TEXT; @@ -3480,21 +3422,7 @@ Text_t compile(env_t *env, ast_t *ast) { return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")), ")"); } else if (t->tag == StructType) { - DeclareMatch(struct_, t, StructType); - if (struct_->opaque) code_err(ast, "This struct is opaque, so I don't know what's inside it!"); - - call_opts_t constructor_opts = { - .promotion = true, - .underscores = (env->current_type != NULL && type_eq(env->current_type, t)), - }; - if (is_valid_call(env, struct_->fields, call->args, constructor_opts)) { - return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args), - "})"); - } else if (!constructor_opts.underscores - && is_valid_call(env, struct_->fields, call->args, - (call_opts_t){.promotion = true, .underscores = true})) { - code_err(ast, "This constructor uses private fields that are not exposed."); - } + return compile_struct_literal(env, ast, t, call->args); } code_err(ast, "I could not find a constructor matching these arguments " @@ -3809,37 +3737,10 @@ Text_t compile(env_t *env, ast_t *ast) { code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values"); } case StructType: { - for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) { - if (streq(field->name, f->field)) { - if (fielded_t->tag == PointerType) { - Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); - return Texts("(", fielded, ")->", valid_c_name(f->field)); - } else { - Text_t fielded = compile(env, f->fielded); - return Texts("(", fielded, ").", valid_c_name(f->field)); - } - } - } - code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_str(value_t)); + return compile_struct_field_access(env, ast); } case EnumType: { - DeclareMatch(e, value_t, EnumType); - for (tag_t *tag = e->tags; tag; tag = tag->next) { - if (streq(f->field, tag->name)) { - Text_t tag_name = namespace_name(e->env, e->env->namespace, Texts("tag$", tag->name)); - if (fielded_t->tag == PointerType) { - Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); - return Texts("((", fielded, ")->$tag == ", tag_name, ")"); - } else if (enum_has_fields(value_t)) { - Text_t fielded = compile(env, f->fielded); - return Texts("((", fielded, ").$tag == ", tag_name, ")"); - } else { - Text_t fielded = compile(env, f->fielded); - return Texts("((", fielded, ") == ", tag_name, ")"); - } - } - } - code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_str(value_t)); + return compile_enum_field_access(env, ast); } case ListType: { if (streq(f->field, "length")) diff --git a/src/compile.h b/src/compile.h index 56b522c7..6b0b4dc5 100644 --- a/src/compile.h +++ b/src/compile.h @@ -7,18 +7,20 @@ #include "environment.h" #include "stdlib/datatypes.h" -Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t); -Text_t expr_as_text(Text_t expr, type_t *t, Text_t color); +Text_t compile(env_t *env, ast_t *ast); +Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version); +Text_t compile_declaration(type_t *t, Text_t name); +Text_t compile_empty(type_t *t); Text_t compile_file(env_t *env, ast_t *ast); Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast); -Text_t compile_declaration(type_t *t, Text_t name); -Text_t compile_type(type_t *t); -Text_t compile(env_t *env, ast_t *ast); Text_t compile_namespace_header(env_t *env, const char *ns_name, ast_t *block); Text_t compile_statement(env_t *env, ast_t *ast); -Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast); Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast); +Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast); +Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t); +Text_t compile_type(type_t *t); Text_t compile_type_info(type_t *t); -Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version); +Text_t expr_as_text(Text_t expr, type_t *t, Text_t color); +Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/compile/enums.c b/src/compile/enums.c index 3abe0307..c28aafae 100644 --- a/src/compile/enums.c +++ b/src/compile/enums.c @@ -9,6 +9,7 @@ #include "../stdlib/tables.h" #include "../stdlib/text.h" #include "../typecheck.h" +#include "pointer.h" #include "structs.h" Text_t compile_enum_typeinfo(env_t *env, ast_t *ast) { @@ -140,4 +141,41 @@ Text_t compile_enum_header(env_t *env, ast_t *ast) { return all_defs; } +public +Text_t compile_empty_enum(type_t *t) { + DeclareMatch(enum_, t, EnumType); + tag_t *tag = enum_->tags; + assert(tag); + assert(tag->type); + if (Match(tag->type, StructType)->fields) + return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", + compile_empty(tag->type), "})"); + else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})"); + else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")"); +} + +public +Text_t compile_enum_field_access(env_t *env, ast_t *ast) { + DeclareMatch(f, ast, FieldAccess); + type_t *fielded_t = get_type(env, ast); + type_t *value_t = value_type(fielded_t); + DeclareMatch(e, value_t, EnumType); + for (tag_t *tag = e->tags; tag; tag = tag->next) { + if (streq(f->field, tag->name)) { + Text_t tag_name = namespace_name(e->env, e->env->namespace, Texts("tag$", tag->name)); + if (fielded_t->tag == PointerType) { + Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); + return Texts("((", fielded, ")->$tag == ", tag_name, ")"); + } else if (enum_has_fields(value_t)) { + Text_t fielded = compile(env, f->fielded); + return Texts("((", fielded, ").$tag == ", tag_name, ")"); + } else { + Text_t fielded = compile(env, f->fielded); + return Texts("((", fielded, ") == ", tag_name, ")"); + } + } + } + code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_str(value_t)); +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/compile/enums.h b/src/compile/enums.h index 6a42bece..c272086a 100644 --- a/src/compile/enums.h +++ b/src/compile/enums.h @@ -6,8 +6,10 @@ #include "../environment.h" #include "../stdlib/datatypes.h" -Text_t compile_enum_typeinfo(env_t *env, ast_t *ast); +Text_t compile_empty_enum(type_t *t); Text_t compile_enum_constructors(env_t *env, ast_t *ast); +Text_t compile_enum_field_access(env_t *env, ast_t *ast); Text_t compile_enum_header(env_t *env, ast_t *ast); +Text_t compile_enum_typeinfo(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/compile/pointer.c b/src/compile/pointer.c new file mode 100644 index 00000000..50c267b6 --- /dev/null +++ b/src/compile/pointer.c @@ -0,0 +1,49 @@ +// Compilation logic +#include <gc.h> +#include <glob.h> +#include <gmp.h> +#include <uninorm.h> + +#include "../ast.h" +#include "../compile.h" +#include "../config.h" +#include "../environment.h" +#include "../stdlib/text.h" +#include "../typecheck.h" +#include "list.h" + +Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) { + Text_t val = compile(env, ast); + type_t *t = get_type(env, ast); + int64_t depth = 0; + for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed) + ++depth; + + // Passing a literal value won't trigger an incref, because it's ephemeral, + // e.g. [10, 20].reversed() + if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false; + + while (depth != target_depth) { + if (depth < target_depth) { + if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")"); + else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast))); + t = Type(PointerType, .pointed = t, .is_stack = true); + ++depth; + } else { + DeclareMatch(ptr, t, PointerType); + val = Texts("*(", val, ")"); + t = ptr->pointed; + --depth; + } + } + + while (t->tag == PointerType) { + DeclareMatch(ptr, t, PointerType); + t = ptr->pointed; + } + + if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")"); + else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")"); + + return val; +} diff --git a/src/compile/pointer.h b/src/compile/pointer.h new file mode 100644 index 00000000..306c3019 --- /dev/null +++ b/src/compile/pointer.h @@ -0,0 +1,6 @@ +#include <stdbool.h> + +#include "../environment.h" +#include "../stdlib/datatypes.h" + +Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref); diff --git a/src/compile/structs.c b/src/compile/structs.c index d4bb346c..d7cbcddf 100644 --- a/src/compile/structs.c +++ b/src/compile/structs.c @@ -8,7 +8,9 @@ #include "../stdlib/tables.h" #include "../stdlib/text.h" #include "../typecheck.h" +#include "pointer.h" +public Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque) { Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(name, "$$info")); @@ -44,6 +46,7 @@ Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_ return Texts(typeinfo, "};\n"); } +public Text_t compile_struct_header(env_t *env, ast_t *ast) { DeclareMatch(def, ast, StructDef); Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(def->name, "$$info")); @@ -77,4 +80,57 @@ Text_t compile_struct_header(env_t *env, ast_t *ast) { } return Texts(struct_code, optional_code, typeinfo_code); } + +public +Text_t compile_empty_struct(type_t *t) { + DeclareMatch(struct_, t, StructType); + Text_t code = Texts("((", compile_type(t), "){"); + for (arg_t *field = struct_->fields; field; field = field->next) { + Text_t empty_field = + field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type); + if (empty_field.length == 0) return EMPTY_TEXT; + + code = Texts(code, empty_field); + if (field->next) code = Texts(code, ", "); + } + return Texts(code, "})"); +} + +public +Text_t compile_struct_field_access(env_t *env, ast_t *ast) { + DeclareMatch(f, ast, FieldAccess); + type_t *fielded_t = get_type(env, ast); + type_t *value_t = value_type(fielded_t); + for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) { + if (streq(field->name, f->field)) { + if (fielded_t->tag == PointerType) { + Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); + return Texts("(", fielded, ")->", valid_c_name(f->field)); + } else { + Text_t fielded = compile(env, f->fielded); + return Texts("(", fielded, ").", valid_c_name(f->field)); + } + } + } + code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_str(value_t)); +} + +public +Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args) { + DeclareMatch(struct_, t, StructType); + if (struct_->opaque) code_err(ast, "This struct is opaque, so I don't know what's inside it!"); + + call_opts_t constructor_opts = { + .promotion = true, + .underscores = (env->current_type != NULL && type_eq(env->current_type, t)), + }; + if (is_valid_call(env, struct_->fields, args, constructor_opts)) { + return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, args), "})"); + } else if (!constructor_opts.underscores + && is_valid_call(env, struct_->fields, args, (call_opts_t){.promotion = true, .underscores = true})) { + code_err(ast, "This constructor uses private fields that are not exposed."); + } + code_err(ast, "I could not find a constructor matching these arguments for the struct ", type_to_str(t)); +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/compile/structs.h b/src/compile/structs.h index f24ed15a..8185b561 100644 --- a/src/compile/structs.h +++ b/src/compile/structs.h @@ -5,8 +5,11 @@ #include "../ast.h" #include "../environment.h" +Text_t compile_empty_struct(type_t *t); Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque); Text_t compile_struct_header(env_t *env, ast_t *ast); +Text_t compile_struct_field_access(env_t *env, ast_t *ast); +Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
