diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-02-25 14:35:25 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-02-25 14:35:25 -0500 |
| commit | d06c63c70c67af6db46cd2a1e3ed002e4b280a8b (patch) | |
| tree | 5e6eca9c2f42b4b9a00037e216cdd79033db5b32 | |
| parent | 5344789d8aed3beef2cdeaf2678cff554e29456a (diff) | |
Table field access for .keys, .values, .default, .fallback
| -rw-r--r-- | compile.c | 20 | ||||
| -rw-r--r-- | test/tables.tm | 31 | ||||
| -rw-r--r-- | types.c | 13 |
3 files changed, 56 insertions, 8 deletions
@@ -886,6 +886,26 @@ CORD compile(env_t *env, ast_t *ast) } code_err(ast, "The field '%s' is not a valid field name of %T", f->field, value_t); } + case TableType: { + if (streq(f->field, "keys")) { + return CORD_all("({ table_t $t = ", compile_to_pointer_depth(env, f->fielded, 0, false), ";\n" + "(array_t){.data = $t.entries.data,\n .length=$t.entries.length,\n .stride=$t.entries.stride,\n .copy_on_write=yes};})"); + } else if (streq(f->field, "values")) { + auto table = Match(value_t, TableType); + size_t offset = type_size(table->key_type); + size_t align = type_align(table->value_type); + if (align > 1 && offset % align > 0) + offset += align - (offset % align); + return CORD_all("({ table_t $t = ", compile_to_pointer_depth(env, f->fielded, 0, false), ";\n" + "(array_t){.data = $t.entries.data + ", CORD_asprintf("%zu", offset), + ",\n .length=$t.entries.length,\n .stride=$t.entries.stride,\n .copy_on_write=yes};})"); + } else if (streq(f->field, "fallback")) { + return CORD_all("(", compile_to_pointer_depth(env, f->fielded, 0, false), ").fallback"); + } else if (streq(f->field, "default")) { + return CORD_all("(", compile_to_pointer_depth(env, f->fielded, 0, false), ").default_value"); + } + code_err(ast, "There is no '%s' field on tables", f->field); + } default: code_err(ast, "Field accesses are only supported on struct and enum values"); } diff --git a/test/tables.tm b/test/tables.tm new file mode 100644 index 00000000..5b53fc80 --- /dev/null +++ b/test/tables.tm @@ -0,0 +1,31 @@ + +>> t := {"one"=>1, "two"=>2; default=999} += {"one"=>1, "two"=>2; default=999} +>> t["one"] += 1 +>> t["two"] += 2 +>> t["???"] += 999 +>> t.default += ?(readonly)999 +>> t.fallback += !{Str=>Int64} + +>> t.keys += ["one", "two"] +>> t.values += [1, 2] + +>> t2 := {"three"=>3; fallback=t} += {"three"=>3; fallback={"one"=>1, "two"=>2; default=999}} +>> t2["one"] += 1 +>> t2["three"] += 3 +>> t2["???"] += 999 +>> t2.default += !Int64 +>> t2.fallback += ?(readonly){"one"=>1, "two"=>2; default=999} @@ -524,18 +524,15 @@ type_t *get_field_type(type_t *t, const char *field_name) } return NULL; } - case ArrayType: { - if (streq(field_name, "length")) - return Type(IntType, .bits=64); - return NULL; - } case TableType: { - if (streq(field_name, "length")) - return Type(IntType, .bits=64); - else if (streq(field_name, "keys")) + if (streq(field_name, "keys")) return Type(ArrayType, Match(t, TableType)->key_type); else if (streq(field_name, "values")) return Type(ArrayType, Match(t, TableType)->value_type); + else if (streq(field_name, "default")) + return Type(PointerType, .pointed=Match(t, TableType)->value_type, .is_readonly=true, .is_optional=true); + else if (streq(field_name, "fallback")) + return Type(PointerType, .pointed=t, .is_readonly=true, .is_optional=true); return NULL; } default: return NULL; |
