diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-03-05 18:20:54 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-03-05 18:20:54 -0500 |
| commit | 147e0f0269440fce15d6b88a8a90627f3a3b2df2 (patch) | |
| tree | bc33522ba71b5a2996fae22e102cce5046cf1333 /compile.c | |
| parent | 2c4324670ff569ede360d13875c5e4b5720a626d (diff) | |
Overhaul of constructors, making it more consistent and correct. Also
changed T(), T, T_t, T_s type names to T(), T$$info, T$$type, T$$struct
for unambiguity
Diffstat (limited to 'compile.c')
| -rw-r--r-- | compile.c | 191 |
1 files changed, 64 insertions, 127 deletions
@@ -13,6 +13,7 @@ #include "enums.h" #include "environment.h" #include "stdlib/integers.h" +#include "stdlib/nums.h" #include "stdlib/patterns.h" #include "stdlib/text.h" #include "stdlib/util.h" @@ -102,22 +103,20 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * return true; } - if (actual->tag == IntType && needed->tag == BigIntType) { - *code = CORD_all("I(", *code, ")"); - return true; - } - - if ((actual->tag == IntType || actual->tag == BigIntType) && needed->tag == NumType) { - *code = CORD_all(type_to_cord(actual), "_to_", type_to_cord(needed), "(", *code, ")"); - return true; + // Numeric promotions/demotions + if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) { + arg_ast_t *args = new(arg_ast_t, .value=FakeAST(InlineCCode, .code=*code, .type=actual)); + binding_t *constructor = NULL; + if ((constructor=get_constructor(env, needed, args, needed)) + || (constructor=get_constructor(env, actual, args, needed))) { + auto fn = Match(constructor->type, FunctionType); + if (fn->args->next == NULL) { + *code = CORD_all(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return true; + } + } } - if (actual->tag == NumType && needed->tag == IntType) - return false; - - if (actual->tag == IntType || actual->tag == NumType) - return true; - if (needed->tag == EnumType) { const char *tag = enum_single_value_tag(needed, actual); binding_t *b = get_binding(Match(needed, EnumType)->env, tag); @@ -527,7 +526,7 @@ CORD compile_type(type_t *t) else if (streq(text->lang, "Shell")) return "Shell_t"; else - return CORD_all(namespace_prefix(text->env, text->env->namespace->parent), text->lang, "_t"); + return CORD_all(namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$type"); } case ArrayType: return "Array_t"; case SetType: return "Table_t"; @@ -547,11 +546,11 @@ CORD compile_type(type_t *t) case PointerType: return CORD_cat(compile_type(Match(t, PointerType)->pointed), "*"); case StructType: { auto s = Match(t, StructType); - return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "_s"); + return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$struct"); } case EnumType: { auto e = Match(t, EnumType); - return CORD_all(namespace_prefix(e->env, e->env->namespace->parent), e->name, "_t"); + return CORD_all(namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$type"); } case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; @@ -570,7 +569,7 @@ CORD compile_type(type_t *t) if (nonnull == MATCH_TYPE) return "OptionalMatch_t"; auto s = Match(nonnull, StructType); - return CORD_all(namespace_prefix(s->env, s->env->namespace->parent), "$Optional", s->name, "_t"); + return CORD_all(namespace_prefix(s->env, s->env->namespace->parent), "$Optional", s->name, "$$type"); } default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: %T", t); @@ -1848,10 +1847,18 @@ CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool CORD compile_to_type(env_t *env, ast_t *ast, type_t *t) { - if (ast->tag == Int && is_numeric_type(t)) + if (ast->tag == Int && is_numeric_type(t)) { return compile_int_to_type(env, ast, t); - if (ast->tag == None && Match(ast, None)->type == NULL) + } else if (ast->tag == Num && t->tag == NumType) { + double n = Match(ast, Num)->n; + switch (Match(t, NumType)->bits) { + case TYPE_NBITS64: return CORD_asprintf("N64(%.20g)", n); + case TYPE_NBITS32: return CORD_asprintf("N32(%.10g)", n); + default: code_err(ast, "This is not a valid number bit width"); + } + } else if (ast->tag == None && Match(ast, None)->type == NULL) { return compile_none(t); + } type_t *actual = get_type(env, ast); @@ -1886,7 +1893,7 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target) CORD code = compile(env, ast); type_t *actual_type = get_type(env, ast); if (!promote(env, ast, &code, actual_type, target)) - code = CORD_all(type_to_cord(actual_type), "_to_", type_to_cord(target), "(", code, ", no)"); + code_err(ast, "I couldn't promote this %T to a %T", actual_type, target); return code; } @@ -1968,9 +1975,10 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str); if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer"); - double n = Int_to_Num(int_val); - value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64 - ? "N64(%.20g)" : "N32(%.10g)", n); + if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64) + value = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false)); + else + value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false)); } else { env_t *arg_env = with_enum_scope(env, spec_arg->type); value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type); @@ -1994,9 +2002,10 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str); if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer"); - double n = Int_to_Num(int_val); - value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64 - ? "N64(%.20g)" : "N32(%.10g)", n); + if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64) + value = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false)); + else + value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false)); } else { env_t *arg_env = with_enum_scope(env, spec_arg->type); value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type); @@ -2226,22 +2235,6 @@ static ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject) return WrapAST(item, MethodCall, .name="add", .self=subject, .args=new(arg_ast_t, .value=item)); } -static CORD compile_num_to_type(ast_t *ast, type_t *type) -{ - double n = Match(ast, Num)->n; - - if (type->tag != NumType) - code_err(ast, "I can't compile a number literal to a %T", type); - - switch (Match(type, NumType)->bits) { - case TYPE_NBITS64: - return CORD_asprintf("N64(%.20g)", n); - case TYPE_NBITS32: - return CORD_asprintf("N32(%.10g)", n); - default: code_err(ast, "This is not a valid number bit width"); - } -} - CORD compile(env_t *env, ast_t *ast) { switch (ast->tag) { @@ -2273,7 +2266,7 @@ CORD compile(env_t *env, ast_t *ast) if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) { return CORD_asprintf("I_small(%s)", str); } else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) { - return CORD_asprintf("Int64_to_Int(%s)", str); + return CORD_asprintf("Int$from_int64(%s)", str); } else { return CORD_asprintf("Int$from_str(\"%s\")", str); } @@ -3012,7 +3005,6 @@ CORD compile(env_t *env, ast_t *ast) if (entry->b->type->tag == ModuleType) continue; binding_t *b = get_binding(env, entry->name); - if (!b) printf("Couldn't find: %s\n", entry->name); assert(b); CORD binding_code = b->code; if (entry->b->type->tag == ArrayType) @@ -3371,6 +3363,12 @@ CORD compile(env_t *env, ast_t *ast) } else if (fn_t->tag == TypeInfoType) { type_t *t = Match(fn_t, TypeInfoType)->type; + // Literal constructors for numeric types like `Byte(123)` should not go through any conversion, just a cast: + if (is_numeric_type(t) && call->args && !call->args->next && call->args->value->tag == Int) + return compile_to_type(env, call->args->value, t); + else if (t->tag == NumType && call->args && !call->args->next && call->args->value->tag == Num) + return compile_to_type(env, call->args->value, t); + binding_t *constructor = get_constructor(env, t, call->args, t); if (constructor) { arg_t *arg_spec = Match(constructor->type, FunctionType)->args; @@ -3378,65 +3376,7 @@ CORD compile(env_t *env, ast_t *ast) } type_t *actual = call->args ? get_type(env, call->args->value) : NULL; - if (t->tag == StructType) { - // Struct constructor: - fn_t = Type(FunctionType, .args=Match(t, StructType)->fields, .ret=t); - return CORD_all("((", compile_type(t), "){", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), "})"); - } else if (is_numeric_type(t) && call->args && call->args->value->tag == Int) { - if (call->args->next) - code_err(call->args->next->value, "This is too many arguments to an integer literal constructor"); - return compile_int_to_type(env, call->args->value, t); - } else if (t->tag == NumType && call->args && call->args->value->tag == Num) { - if (call->args->next) - code_err(call->args->next->value, "This is too many arguments to a number literal constructor"); - return compile_num_to_type(call->args->value, t); - } else if (t->tag == NumType || t->tag == BigIntType) { - if (!call->args) code_err(ast, "This constructor needs a value"); - if (!call->args) - code_err(ast, "This constructor requires an argument!"); - - if (type_eq(actual, t)) { - if (call->args->next) - code_err(ast, "This is too many arguments!"); - return compile(env, call->args->value); - } - - arg_t *args = new(arg_t, .name="i", .type=actual); // No truncation argument - CORD arg_code = compile_arguments(env, ast, args, call->args); - if (is_numeric_type(actual)) { - return CORD_all(type_to_cord(actual), "_to_", type_to_cord(t), "(", arg_code, ")"); - } else if (actual->tag == BoolType) { - if (t->tag == NumType) { - return CORD_all("((", compile_type(t), ")(", arg_code, "))"); - } else { - return CORD_all("I((int)(", arg_code, "))"); - } - } else { - code_err(ast, "You cannot convert a %T to a %T this way.", actual, t); - } - } else if (t->tag == IntType || t->tag == ByteType) { - if (!call->args) - code_err(ast, "This constructor requires an argument!"); - - if (type_eq(actual, t)) { - if (call->args->next) - code_err(ast, "This is too many arguments!"); - return compile(env, call->args->value); - } - - if (is_numeric_type(actual)) { - arg_t *args = new(arg_t, .name="i", .type=actual, .next=new(arg_t, .name="truncate", .type=Type(BoolType), - .default_val=FakeAST(Bool, false))); - CORD arg_code = compile_arguments(env, ast, args, call->args); - return CORD_all(type_to_cord(actual), "_to_", type_to_cord(t), "(", arg_code, ")"); - } else if (actual->tag == BoolType) { - arg_t *args = new(arg_t, .name="i", .type=actual); - CORD arg_code = compile_arguments(env, ast, args, call->args); - return CORD_all("((", compile_type(t),")(", arg_code, "))"); - } else { - code_err(ast, "You cannot convert a %T to a %T this way.", actual, t); - } - } else if (t->tag == TextType) { + if (t->tag == TextType) { if (!call->args) code_err(ast, "This constructor needs a value"); const char *lang = Match(t, TextType)->lang; if (lang) @@ -3458,11 +3398,6 @@ CORD compile(env_t *env, ast_t *ast) else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL) return compile_string_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->cord); return CORD_all("Text$as_c_string(", expr_as_text(env, compile(env, call->args->value), actual, "no"), ")"); - } else if (t->tag == MomentType) { - // Moment constructor: - binding_t *new_binding = get_binding(Match(fn_t, TypeInfoType)->env, "new"); - CORD arg_code = compile_arguments(env, ast, Match(new_binding->type, FunctionType)->args, call->args); - return CORD_all(new_binding->code, "(", arg_code, ")"); } else { code_err(call->fn, "This is not a type that has a constructor"); } @@ -3726,7 +3661,7 @@ CORD compile(env_t *env, ast_t *ast) CORD text = compile_to_pointer_depth(env, f->fielded, 0, false); return CORD_all("((Text_t)", text, ")"); } else if (streq(f->field, "length")) { - return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); } code_err(ast, "There is no '%s' field on %T values", f->field, value_t); } @@ -3763,19 +3698,19 @@ CORD compile(env_t *env, ast_t *ast) } case ArrayType: { if (streq(f->field, "length")) - return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); code_err(ast, "There is no %s field on arrays", f->field); } case SetType: { if (streq(f->field, "items")) return CORD_all("ARRAY_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); else if (streq(f->field, "length")) - return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); code_err(ast, "There is no '%s' field on sets", f->field); } case TableType: { if (streq(f->field, "length")) { - return CORD_all("Int64_to_Int((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); } else if (streq(f->field, "keys")) { return CORD_all("ARRAY_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); } else if (streq(f->field, "values")) { @@ -3835,12 +3770,14 @@ CORD compile(env_t *env, ast_t *ast) type_t *item_type = Match(container_t, ArrayType)->item_type; CORD arr = compile_to_pointer_depth(env, indexing->indexed, 0, false); file_t *f = indexing->index->file; + CORD index_code = indexing->index->tag == Int + ? compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)) + : (index_t->tag == BigIntType ? CORD_all("Int64$from_int(", compile(env, indexing->index), ", no)") + : CORD_all("(Int64_t)(", compile(env, indexing->index), ")")); if (indexing->unchecked) - return CORD_all("Array_get_unchecked(", compile_type(item_type), ", ", arr, ", ", - compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ")"); + return CORD_all("Array_get_unchecked(", compile_type(item_type), ", ", arr, ", ", index_code, ")"); else - return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ", - compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ", ", + return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ", index_code, ", ", CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ", CORD_asprintf("%ld", (int64_t)(indexing->index->end - f->text)), ")"); @@ -3912,15 +3849,15 @@ CORD compile_type_info(env_t *env, type_t *t) return "&Shell$info"; else if (streq(text->lang, "Path")) return "&Path$info"; - return CORD_all("(&", namespace_prefix(text->env, text->env->namespace->parent), text->lang, ")"); + return CORD_all("(&", namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$info)"); } case StructType: { auto s = Match(t, StructType); - return CORD_all("(&", namespace_prefix(s->env, s->env->namespace->parent), s->name, ")"); + return CORD_all("(&", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$info)"); } case EnumType: { auto e = Match(t, EnumType); - return CORD_all("(&", namespace_prefix(e->env, e->env->namespace->parent), e->name, ")"); + return CORD_all("(&", namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$info)"); } case ArrayType: { type_t *item_t = Match(t, ArrayType)->item_type; @@ -4295,7 +4232,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast) } case LangDef: { auto def = Match(ast, LangDef); - CORD code = CORD_asprintf("public const TypeInfo_t %r%s = {%zu, %zu, .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={%r}};\n", + CORD code = CORD_asprintf("public const TypeInfo_t %r%s$$info = {%zu, %zu, .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={%r}};\n", namespace_prefix(env, env->namespace), def->name, sizeof(Text_t), __alignof__(Text_t), CORD_quoted(def->name)); env_t *ns_env = namespace_env(env, def->name); @@ -4429,9 +4366,9 @@ CORD compile_statement_type_header(env_t *env, ast_t *ast) return CORD_all( // Constructor macro: "#define ", namespace_prefix(env, env->namespace), def->name, - "(text) ((", namespace_prefix(env, env->namespace), def->name, "_t){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n" + "(text) ((", namespace_prefix(env, env->namespace), def->name, "$$type){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n" "#define ", namespace_prefix(env, env->namespace), def->name, - "s(...) ((", namespace_prefix(env, env->namespace), def->name, "_t)Texts(__VA_ARGS__))\n" + "s(...) ((", namespace_prefix(env, env->namespace), def->name, "$$type)Texts(__VA_ARGS__))\n" "extern const TypeInfo_t ", full_name, ";\n" ); } @@ -4539,19 +4476,19 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) if (ast->tag == StructDef) { auto def = Match(ast, StructDef); CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name); - *info->header = CORD_all(*info->header, "typedef struct ", full_name, "_s ", full_name, "_t;\n"); + *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"); } else if (ast->tag == EnumDef) { auto def = Match(ast, EnumDef); CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name); - *info->header = CORD_all(*info->header, "typedef struct ", full_name, "_s ", full_name, "_t;\n"); + *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; - *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$", tag->name, "_s ", full_name, "$", tag->name, "_t;\n"); + *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$", tag->name, "$$struct ", full_name, "$", tag->name, "$$type;\n"); } } else if (ast->tag == LangDef) { auto def = Match(ast, LangDef); - *info->header = CORD_all(*info->header, "typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "_t;\n"); + *info->header = CORD_all(*info->header, "typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "$$type;\n"); } } |
