aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-02-25 14:35:25 -0500
committerBruce Hill <bruce@bruce-hill.com>2024-02-25 14:35:25 -0500
commitd06c63c70c67af6db46cd2a1e3ed002e4b280a8b (patch)
tree5e6eca9c2f42b4b9a00037e216cdd79033db5b32
parent5344789d8aed3beef2cdeaf2678cff554e29456a (diff)
Table field access for .keys, .values, .default, .fallback
-rw-r--r--compile.c20
-rw-r--r--test/tables.tm31
-rw-r--r--types.c13
3 files changed, 56 insertions, 8 deletions
diff --git a/compile.c b/compile.c
index a9a0d2c7..0ed42f69 100644
--- a/compile.c
+++ b/compile.c
@@ -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}
diff --git a/types.c b/types.c
index 1fd671f1..5e37536b 100644
--- a/types.c
+++ b/types.c
@@ -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;