diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-02-18 04:26:26 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-02-18 04:26:26 -0500 |
| commit | 5ce55a6a29b240e7f0818fff0475f924188c74c8 (patch) | |
| tree | 6bcf53929257a8cd1f071ddba54c539c775b66a9 | |
| parent | 30c34a7243db7357733bd11c9ee3a093c35891cc (diff) | |
Better table literals
| -rw-r--r-- | builtins/table.h | 13 | ||||
| -rw-r--r-- | compile.c | 149 | ||||
| -rw-r--r-- | nextlang.h | 2 | ||||
| -rw-r--r-- | types.c | 53 |
4 files changed, 124 insertions, 93 deletions
diff --git a/builtins/table.h b/builtins/table.h index 14893253..13262bbe 100644 --- a/builtins/table.h +++ b/builtins/table.h @@ -7,6 +7,19 @@ #include "datatypes.h" #include "array.h" +#define $Table(key_t, val_t, key_info, value_info, fb, def, ...) ({ \ + struct { key_t k; val_t v; } $ents[] = {__VA_ARGS__}; \ + table_t $table = Table_from_entries((array_t){ \ + .data=memcpy(GC_MALLOC(sizeof($ents)), $ents, sizeof($ents)), \ + .length=sizeof($ents)/sizeof($ents[0]), \ + .stride=(void*)&$ents[1] - (void*)&$ents[0], \ + }, &((TypeInfo){.size=sizeof(table_t), .align=__alignof__(table_t), .tag=TableInfo, \ + .TableInfo.key=key_info, .TableInfo.value=value_info})); \ + $table.fallback = fb; \ + $table.default_value = def; \ + $table; }) + + table_t Table_from_entries(array_t entries, const TypeInfo *type); void *Table_get(const table_t *t, const void *key, const TypeInfo *type); void *Table_get_raw(const table_t *t, const void *key, const TypeInfo *type); @@ -68,16 +68,16 @@ CORD compile_statement(env_t *env, ast_t *ast) CORD expr_as_string(env_t *env, CORD expr, type_t *t, CORD color) { switch (t->tag) { - case MemoryType: return CORD_asprintf("Memory__as_str(%r, %r, NULL)", expr, color); - case BoolType: return CORD_asprintf("Bool__as_str(%r, %r, NULL)", expr, color); - case IntType: return CORD_asprintf("Int%ld__as_str(%r, %r, NULL)", Match(t, IntType)->bits, expr, color); - case NumType: return CORD_asprintf("Num%ld__as_str(%r, %r, NULL)", Match(t, NumType)->bits, expr, color); - case StringType: return CORD_asprintf("Str__as_str(%r, %r, &Str.type)", expr, color); - case ArrayType: return CORD_asprintf("Array__as_str(%r, %r, %r)", expr, color, compile_type_info(env, t)); - case TableType: return CORD_asprintf("Table_as_str(%r, %r, %r)", expr, color, compile_type_info(env, t)); - case FunctionType: return CORD_asprintf("Func__as_str(%r, %r, %r)", expr, color, compile_type_info(env, t)); - case PointerType: return CORD_asprintf("Pointer__as_str(%r, %r, %r)", expr, color, compile_type_info(env, t)); - case StructType: case EnumType: return CORD_asprintf("(%r)->CustomInfo.as_str(%r, %r, %r)", + case MemoryType: return CORD_asprintf("Memory__as_str($stack(%r), %r, NULL)", expr, color); + case BoolType: return CORD_asprintf("Bool__as_str($stack(%r), %r, NULL)", expr, color); + case IntType: return CORD_asprintf("Int%ld__as_str($stack(%r), %r, NULL)", Match(t, IntType)->bits, expr, color); + case NumType: return CORD_asprintf("Num%ld__as_str($stack(%r), %r, NULL)", Match(t, NumType)->bits, expr, color); + case StringType: return CORD_asprintf("Str__as_str($stack(%r), %r, &Str.type)", expr, color); + case ArrayType: return CORD_asprintf("Array__as_str($stack(%r), %r, %r)", expr, color, compile_type_info(env, t)); + case TableType: return CORD_asprintf("Table_as_str($stack(%r), %r, %r)", expr, color, compile_type_info(env, t)); + case FunctionType: return CORD_asprintf("Func__as_str($stack(%r), %r, %r)", expr, color, compile_type_info(env, t)); + case PointerType: return CORD_asprintf("Pointer__as_str($stack(%r), %r, %r)", expr, color, compile_type_info(env, t)); + case StructType: case EnumType: return CORD_asprintf("(%r)->CustomInfo.as_str($stack(%r), %r, %r)", compile_type_info(env, t), expr, color, compile_type_info(env, t)); default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for %T", t); } @@ -320,18 +320,15 @@ CORD compile(env_t *env, ast_t *ast) return compile(env, chunks->ast); return compile_string(env, chunks->ast, "no"); } else { - int64_t num_chunks = 0; - for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) - ++num_chunks; - - CORD code = CORD_asprintf("CORD_catn(%ld", num_chunks); + CORD code = "CORD_all("; for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) { - type_t *chunk_t = get_type(env, chunks->ast); + type_t *chunk_t = get_type(env, chunk->ast); CORD chunk_str = (chunk_t->tag == StringType) ? compile(env, chunk->ast) : compile_string(env, chunk->ast, "no"); - CORD_appendf(&code, ", %r", chunk_str); + code = CORD_cat(code, chunk_str); + if (chunk->next) code = CORD_cat(code, ", "); } - return CORD_cat_char(code, ')'); + return CORD_cat(code, ")"); } } case Block: { @@ -400,18 +397,29 @@ CORD compile(env_t *env, ast_t *ast) } type_t *table_t = get_type(env, ast); - // TODO: figure out a clever way to optimize table literals: - CORD code = CORD_all("({ table_t $table = {}; TypeInfo *$table_type = ", compile_type_info(env, table_t), ";"); + type_t *key_t = Match(table_t, TableType)->key_type; + type_t *value_t = Match(table_t, TableType)->value_type; + CORD code = CORD_all("$Table(", + compile_type(key_t), ", ", + compile_type(value_t), ", ", + compile_type_info(env, key_t), ", ", + compile_type_info(env, value_t), ", /*fallback:*/"); + if (table->fallback) + code = CORD_all(code, "$heap(", compile(env, table->fallback), ");\n"); + else + code = CORD_all(code, "NULL, "); + + code = CORD_cat(code, "/*default:*/"); + if (table->default_value) + code = CORD_all(code, "$heap(", compile(env, table->default_value), ");\n"); + else + code = CORD_all(code, "NULL"); + for (ast_list_t *entry = table->entries; entry; entry = entry->next) { auto entry = Match(entry->ast, TableEntry); - code = CORD_all(code, " Table_set(&$table, $stack(", - compile(env, entry->key), "), $stack(", compile(env, entry->value), "), $table_type);"); + code = CORD_all(code, ",\n\t{", compile(env, entry->key), ", ", compile(env, entry->value), "}"); } - if (table->fallback) - code = CORD_all(code, " $table.fallback = $heap(", compile(env, table->fallback), ");"); - if (table->default_value) - code = CORD_all(code, " $table.default_value = $heap(", compile(env, table->default_value), ");"); - return CORD_cat(code, " $table; })"); + return CORD_cat(code, ")"); } // Table, TableEntry, @@ -477,17 +485,74 @@ CORD compile(env_t *env, ast_t *ast) } case For: { auto for_ = Match(ast, For); - CORD index = for_->index ? compile(env, for_->index) : "$i"; - return CORD_asprintf("{\n" - "$var($iter, %r);\n" - "for (int64_t %r = 1, $len = ($iter).length; %r <= $len; ++%r) {\n" - "$var(%r, $safe_index($iter, %s));\n" - "%r\n" - "}\n}", - compile(env, for_->iter), - index, index, index, - compile(env, for_->value), index, - compile(env, for_->body)); + type_t *iter_t = get_type(env, for_->iter); + switch (iter_t->tag) { + case ArrayType: { + type_t *item_t = Match(iter_t, ArrayType)->item_type; + env_t *scope = fresh_scope(env); + CORD index = for_->index ? compile(env, for_->index) : "$i"; + if (for_->index) + set_binding(scope, CORD_to_const_char_star(index), new(binding_t, .type=Type(IntType, .bits=64))); + CORD value = compile(env, for_->value); + set_binding(scope, CORD_to_const_char_star(value), new(binding_t, .type=item_t)); + return CORD_all( + "{ // For loop:\n" + "array_t $iter = ", compile(env, for_->iter), ";\n" + "for (Int64_t ", index, " = 1; ", index, " <= $iter.length; ++", index, ") {\n" + "\t", compile_type(item_t), " ", value, " = *(", compile_type(item_t), "*)($iter.data + (", index, "-1)*$iter.stride);\n" + "\t", compile(scope, for_->body), "\n" + "}\n" + "}\n"); + } + case TableType: { + type_t *key_t = Match(iter_t, TableType)->key_type; + type_t *value_t = Match(iter_t, TableType)->value_type; + env_t *scope = fresh_scope(env); + CORD key, value; + if (for_->index) { + key = compile(env, for_->index); + value = compile(env, for_->value); + set_binding(scope, CORD_to_const_char_star(key), new(binding_t, .type=key_t)); + set_binding(scope, CORD_to_const_char_star(value), new(binding_t, .type=value_t)); + + size_t value_offset = type_size(key_t); + if (type_align(value_t) > 1 && value_offset % type_align(value_t)) + value_offset += type_align(value_t) - (value_offset % type_align(value_t)); // padding + return CORD_all( + "{ // For loop:\n" + "array_t $entries = (", compile(env, for_->iter), ").entries;\n" + "for (Int64_t $offset = 0; $offset < $entries.length; ++$offset) {\n" + "\t", compile_type(key_t), " ", key, " = *(", compile_type(key_t), "*)($entries.data + $offset*$entries.stride);\n" + "\t", compile_type(value_t), " ", value, " = *(", compile_type(value_t), "*)($entries.data + $offset*$entries.stride + ", CORD_asprintf("%zu", value_offset), ");\n" + "\t", compile(scope, for_->body), "\n" + "}\n" + "}\n"); + } else { + key = compile(env, for_->index); + set_binding(scope, CORD_to_const_char_star(key), new(binding_t, .type=key_t)); + return CORD_all( + "{ // For loop:\n" + "array_t $entries = (", compile(env, for_->iter), ").entries;\n" + "for (Int64_t $offset = 0; $offset < $entries.length; ++$offset) {\n" + "\t", compile_type(key_t), " ", key, " = *(", compile_type(key_t), "*)$entries.data + $offset*$entries.stride);\n" + "\t", compile(scope, for_->body), "\n" + "}\n" + "}\n"); + } + } + case IntType: { + type_t *item_t = iter_t; + env_t *scope = fresh_scope(env); + if (for_->index) + code_err(for_->index, "It's redundant to have a separate iteration index"); + CORD value = compile(env, for_->value); + set_binding(scope, CORD_to_const_char_star(value), new(binding_t, .type=item_t)); + return CORD_all( + "for (Int64_t ", value, " = 1, $n = ", compile(env, for_->iter), "; ", value, " <= $n; ++", value, ")\n" + "\t", compile(scope, for_->body), "\n"); + } + default: code_err(for_->iter, "Iteration is not implemented for type: %T", iter_t); + } } // For, // Reduction, @@ -533,7 +598,7 @@ CORD compile(env_t *env, ast_t *ast) CORD_appendf(&cord_func, "\treturn CORD_all(use_color ? \"\\x1b[0;1m%s\\x1b[m(\" : \"%s(\"", def->name, def->name); for (arg_ast_t *field = def->fields; field; field = field->next) { type_t *field_t = parse_type_ast(env, field->type); - CORD field_str = expr_as_string(env, CORD_cat("&obj->", field->name), field_t, "use_color"); + CORD field_str = expr_as_string(env, CORD_cat("obj->", field->name), field_t, "use_color"); CORD_appendf(&cord_func, ", \"%s=\", %r", field->name, field_str); if (field->next) CORD_appendf(&cord_func, ", \", \""); } @@ -574,7 +639,7 @@ CORD compile(env_t *env, ast_t *ast) for (arg_ast_t *field = tag->fields; field; field = field->next) { type_t *field_t = parse_type_ast(env, field->type); - CORD field_str = expr_as_string(env, CORD_all("&obj->", tag->name, ".", field->name), field_t, "use_color"); + CORD field_str = expr_as_string(env, CORD_all("obj->", tag->name, ".", field->name), field_t, "use_color"); CORD_appendf(&cord_func, ", \"%s=\", %r", field->name, field_str); if (field->next) CORD_appendf(&cord_func, ", \", \""); } @@ -619,7 +684,7 @@ CORD compile(env_t *env, ast_t *ast) CORD expr_cord = "CORD_all("; i = 1; for (ast_list_t *target = assign->targets; target; target = target->next) { - CORD item = expr_as_string(env, CORD_asprintf("&$%ld", i++), get_type(env, target->ast), "USE_COLOR"); + CORD item = expr_as_string(env, CORD_asprintf("$%ld", i++), get_type(env, target->ast), "USE_COLOR"); expr_cord = CORD_all(expr_cord, item, target->next ? ", \", \", " : CORD_EMPTY); } expr_cord = CORD_cat(expr_cord, ")"); @@ -703,7 +768,7 @@ CORD compile_type_info(env_t *env, type_t *t) sigil, compile_type_info(env, ptr->pointed)); } case FunctionType: { - return CORD_asprintf("&((TypeInfo){.size=%zu, .align=%zu, .tag=FunctionInfo, .FunctionInfo.type_str=\"%r\"})", + return CORD_asprintf("((TypeInfo){.size=%zu, .align=%zu, .tag=FunctionInfo, .FunctionInfo.type_str=\"%r\"})", sizeof(void*), __alignof__(void*), type_to_cord(t)); } case ClosureType: { @@ -63,7 +63,7 @@ CORD as_cord(void *x, bool use_color, const char *fmt, ...); #define min(x, y) ({ $var($min_lhs, x); $var($min_rhs, y); $le($min_lhs, $min_rhs) ? $min_lhs : $min_rhs; }) #define max(x, y) ({ $var($min_lhs, x); $var($min_rhs, y); $ge($min_lhs, $min_rhs) ? $min_lhs : $min_rhs; }) -#define say(str) puts(CORD_to_const_char_star($cord(str))) +#define say(str) CORD_put(CORD_cat(str, "\n"), stdout) #define $test(src, expr, expected) do { \ CORD $result = $cord(expr); \ CORD $output = CORD_catn(5, USE_COLOR ? "\x1b[33;1m>>\x1b[0m " : ">> ", src, USE_COLOR ? "\n\x1b[0;2m=\x1b[m " : "\n= ", $result, "\x1b[m"); \ @@ -1,6 +1,7 @@ // Logic for handling type_t types #include <gc/cord.h> #include <stdint.h> +#include <signal.h> #include <limits.h> #include <math.h> @@ -15,6 +16,7 @@ CORD type_to_cord(type_t *t) { case VoidType: return "Void"; case MemoryType: return "Memory"; case BoolType: return "Bool"; + case StringType: return "Str"; case IntType: return CORD_asprintf("Int%ld", Match(t, IntType)->bits); case NumType: return CORD_asprintf("Num%ld", Match(t, NumType)->bits); case ArrayType: { @@ -39,22 +41,6 @@ CORD type_to_cord(type_t *t) { case StructType: { auto struct_ = Match(t, StructType); return struct_->name; - // CORD c = CORD_asprintf("%s(", struct_->name); - // int64_t i = 1; - // for (arg_t *field = struct_->fields; field; field = field->next) { - // const char *fname = field->name ? field->name : heap_strf("_%lu", i); - // ++i; - // if (fname && !streq(fname, heap_strf("_%lu", i+1))) - // c = CORD_cat(CORD_cat(c, fname), ":"); - // else - // c = CORD_cat(c, ":"); - - // c = CORD_cat(c, type_to_cord(field->type)); - - // if (field->next) c = CORD_cat(c, ", "); - // } - // c = CORD_cat(c, ")"); - // return c; } case PointerType: { auto ptr = Match(t, PointerType); @@ -65,45 +51,12 @@ CORD type_to_cord(type_t *t) { case EnumType: { auto tagged = Match(t, EnumType); return tagged->name; - -// CORD c = CORD_asprintf("%s(", tagged->name); -// int64_t next_tag = 0; -// for (tag_t *tag = tagged->tags; tag; tag = tag->next) { -// // name, tag_value, type -// c = CORD_cat(c, tag->name); -// if (tag->type) { -// c = CORD_cat(c, "("); -// auto struct_ = Match(tag->type, StructType); -// int64_t i = 1; -// for (arg_t *field = struct_->fields; field; field = field->next) { -// if (field->name && !streq(field->name, heap_strf("_%lu", i))) -// c = CORD_cat(CORD_cat(c, field->name), ":"); - -// CORD fstr = type_to_cord(field->type); -// c = CORD_cat(c, fstr); -// if (field->next) c = CORD_cat(c, ","); -// ++i; -// } -// c = CORD_cat(c, ")"); -// } - -// if (tag->tag_value != next_tag) { -// CORD_sprintf(&c, "%r=%ld", c, tag->tag_value); -// next_tag = tag->tag_value + 1; -// } else { -// ++next_tag; -// } - -// if (tag->next) -// c = CORD_cat(c, ", "); -// } -// c = CORD_cat(c, ")"); -// return c; } case TypeInfoType: { return "TypeInfo"; } default: { + raise(SIGABRT); return CORD_asprintf("Unknown type: %d", t->tag); } } |
