aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-10-11 15:50:19 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-10-11 15:50:19 -0400
commit436d2e02debe058e9968935e742e397c19de628a (patch)
treec51d08a586ead5c4f22d3f2d12695c4a7cf6cbca
parent7e8604daeb9239e1669c5414dd6caa37af30c4ff (diff)
Improvements to set support and updating docs
-rw-r--r--CHANGES.md9
-rw-r--r--api/api.md8
-rw-r--r--api/lists.md8
-rw-r--r--api/lists.yaml8
-rw-r--r--man/man3/tomo-Byte.to.318
-rw-r--r--man/man3/tomo-List.clear.34
-rw-r--r--man/man3/tomo-List.heap_push.34
-rw-r--r--man/man3/tomo-List.heapify.36
-rw-r--r--man/man3/tomo-List.shuffle.34
-rw-r--r--man/man3/tomo-List.unique.310
-rw-r--r--man/man3/tomo-Path.expand_home.310
-rw-r--r--man/man3/tomo-Text.from_codepoint_names.312
-rw-r--r--man/man3/tomo-Text.translate.320
-rw-r--r--man/man3/tomo-getenv.36
-rw-r--r--src/compile/lists.c2
-rw-r--r--src/stdlib/tables.c13
-rw-r--r--src/typecheck.c3
-rw-r--r--test/lists.tm2
18 files changed, 78 insertions, 69 deletions
diff --git a/CHANGES.md b/CHANGES.md
index fd51056e..f84c3af8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,8 +12,11 @@
- Syntax for tables has changed to use colons (`{k: v}`) instead of equals
(`{k=v}`).
- Deprecated:
- - Sets
- - Instead of sets, use tables.
+ - Sets are no longer a separate type with separate methods.
+ - Instead of sets, use tables with a value type of `{KeyType:Empty}`.
+ - As a shorthand, you can use `{a,b,c}` instead of `{a:Empty(),
+ b:Empty(), c:Empty()}` and the type annotation `{K}` as shorthand for
+ `{K:Empty}`.
- Tables now have `and`, `or`, `xor`, and `-` (minus) metamethods.
- `extern` keyword for declaring external symbols from C.
- Use `C_code` instead.
@@ -31,6 +34,8 @@
`table.intersection(other)`, and `table.difference(other)`.
- Added `Empty` for a built-in empty struct type and `EMPTY` for an instance of
the empty struct.
+- Changed `list.unique()` to return a table with `Empty()` values for each
+ unique list item.
- Added a `--format` flag to the `tomo` binary that autoformats your code
(currently unstable, do not rely on it just yet).
- Standardized text methods for Unicode encodings:
diff --git a/api/api.md b/api/api.md
index 49ca6a5b..eaf8da17 100644
--- a/api/api.md
+++ b/api/api.md
@@ -1266,21 +1266,21 @@ assert [10, 20, 30, 40, 50].to(-2) == [10, 20, 30, 40]
## List.unique
```tomo
-List.unique : func(list: [T] -> [T])
+List.unique : func(list: [T] -> {T})
```
-Returns a list of the unique elements of the list.
+Returns a set of the unique elements of the list.
Argument | Type | Description | Default
---------|------|-------------|---------
list | `[T]` | The list to process. | -
-**Return:** A list of the unique elements from the list.
+**Return:** A set of the unique elements from the list.
**Example:**
```tomo
-assert [10, 20, 10, 10, 30].unique() == [10, 20, 30]
+assert [10, 20, 10, 10, 30].unique() == {10, 20, 30}
```
## List.where
diff --git a/api/lists.md b/api/lists.md
index 3ad61805..1c741989 100644
--- a/api/lists.md
+++ b/api/lists.md
@@ -569,21 +569,21 @@ assert [10, 20, 30, 40, 50].to(-2) == [10, 20, 30, 40]
## List.unique
```tomo
-List.unique : func(list: [T] -> [T])
+List.unique : func(list: [T] -> {T})
```
-Returns a list of the unique elements of the list.
+Returns a set of the unique elements of the list.
Argument | Type | Description | Default
---------|------|-------------|---------
list | `[T]` | The list to process. | -
-**Return:** A list of the unique elements from the list.
+**Return:** A set of the unique elements from the list.
**Example:**
```tomo
-assert [10, 20, 10, 10, 30].unique() == [10, 20, 30]
+assert [10, 20, 10, 10, 30].unique() == {10, 20, 30}
```
## List.where
diff --git a/api/lists.yaml b/api/lists.yaml
index 89769064..5a2bc2a1 100644
--- a/api/lists.yaml
+++ b/api/lists.yaml
@@ -607,18 +607,18 @@ List.to:
List.unique:
short: get the unique items in a list
description: >
- Returns a list of the unique elements of the list.
+ Returns a set of the unique elements of the list.
return:
- type: '[T]'
+ type: '{T}'
description: >
- A list of the unique elements from the list.
+ A set of the unique elements from the list.
args:
list:
type: '[T]'
description: >
The list to process.
example: |
- assert [10, 20, 10, 10, 30].unique() == [10, 20, 30]
+ assert [10, 20, 10, 10, 30].unique() == {10, 20, 30}
List.where:
short: find an index where a predicate matches
diff --git a/man/man3/tomo-Byte.to.3 b/man/man3/tomo-Byte.to.3
index 9982f5da..15774ba7 100644
--- a/man/man3/tomo-Byte.to.3
+++ b/man/man3/tomo-Byte.to.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH Byte.to 3 2025-04-30 "Tomo man-pages"
+.TH Byte.to 3 2025-10-11 "Tomo man-pages"
.SH NAME
Byte.to \- iterate over a range of bytes
.SH LIBRARY
@@ -31,13 +31,13 @@ An iterator function that returns each byte in the given range (inclusive).
.SH EXAMPLES
.EX
->> Byte(2).to(5)
-= func(->Byte?)
->> [x for x in Byte(2).to(5)]
-= [Byte(2), Byte(3), Byte(4), Byte(5)]
->> [x for x in Byte(5).to(2)]
-= [Byte(5), Byte(4), Byte(3), Byte(2)]
+iter := Byte(2).to(4)
+assert iter() == 2
+assert iter() == 3
+assert iter() == 4
+assert iter() == none
->> [x for x in Byte(2).to(5, step=2)]
-= [Byte(2), Byte(4)]
+assert [x for x in Byte(2).to(5)] == [Byte(2), Byte(3), Byte(4), Byte(5)]
+assert [x for x in Byte(5).to(2)] == [Byte(5), Byte(4), Byte(3), Byte(2)]
+assert [x for x in Byte(2).to(5, step=2)] == [Byte(2), Byte(4)]
.EE
diff --git a/man/man3/tomo-List.clear.3 b/man/man3/tomo-List.clear.3
index e912c983..bece5524 100644
--- a/man/man3/tomo-List.clear.3
+++ b/man/man3/tomo-List.clear.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH List.clear 3 2025-04-30 "Tomo man-pages"
+.TH List.clear 3 2025-10-11 "Tomo man-pages"
.SH NAME
List.clear \- clear a list
.SH LIBRARY
@@ -29,5 +29,5 @@ Nothing.
.SH EXAMPLES
.EX
->> my_list.clear()
+my_list.clear()
.EE
diff --git a/man/man3/tomo-List.heap_push.3 b/man/man3/tomo-List.heap_push.3
index 5da4a40a..3c1804bd 100644
--- a/man/man3/tomo-List.heap_push.3
+++ b/man/man3/tomo-List.heap_push.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH List.heap_push 3 2025-04-30 "Tomo man-pages"
+.TH List.heap_push 3 2025-10-11 "Tomo man-pages"
.SH NAME
List.heap_push \- heap push
.SH LIBRARY
@@ -31,5 +31,5 @@ Nothing.
.SH EXAMPLES
.EX
->> my_heap.heap_push(10)
+my_heap.heap_push(10)
.EE
diff --git a/man/man3/tomo-List.heapify.3 b/man/man3/tomo-List.heapify.3
index af7fafd1..345a47b9 100644
--- a/man/man3/tomo-List.heapify.3
+++ b/man/man3/tomo-List.heapify.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH List.heapify 3 2025-04-30 "Tomo man-pages"
+.TH List.heapify 3 2025-10-11 "Tomo man-pages"
.SH NAME
List.heapify \- convert a list into a heap
.SH LIBRARY
@@ -30,6 +30,6 @@ Nothing.
.SH EXAMPLES
.EX
->> my_heap := [30, 10, 20]
->> my_heap.heapify()
+my_heap := [30, 10, 20]
+my_heap.heapify()
.EE
diff --git a/man/man3/tomo-List.shuffle.3 b/man/man3/tomo-List.shuffle.3
index 7d7e1def..875a73c6 100644
--- a/man/man3/tomo-List.shuffle.3
+++ b/man/man3/tomo-List.shuffle.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH List.shuffle 3 2025-04-30 "Tomo man-pages"
+.TH List.shuffle 3 2025-10-11 "Tomo man-pages"
.SH NAME
List.shuffle \- shuffle a list in place
.SH LIBRARY
@@ -30,5 +30,5 @@ Nothing.
.SH EXAMPLES
.EX
->> list.shuffle()
+list.shuffle()
.EE
diff --git a/man/man3/tomo-List.unique.3 b/man/man3/tomo-List.unique.3
index cab945b8..9ed81687 100644
--- a/man/man3/tomo-List.unique.3
+++ b/man/man3/tomo-List.unique.3
@@ -2,17 +2,17 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH List.unique 3 2025-09-21 "Tomo man-pages"
+.TH List.unique 3 2025-10-11 "Tomo man-pages"
.SH NAME
List.unique \- get the unique items in a list
.SH LIBRARY
Tomo Standard Library
.SH SYNOPSIS
.nf
-.BI List.unique\ :\ func(list:\ [T]\ ->\ [T])
+.BI List.unique\ :\ func(list:\ [T]\ ->\ {T})
.fi
.SH DESCRIPTION
-Returns a list of the unique elements of the list.
+Returns a set of the unique elements of the list.
.SH ARGUMENTS
@@ -25,9 +25,9 @@ Name Type Description Default
list [T] The list to process. -
.TE
.SH RETURN
-A list of the unique elements from the list.
+A set of the unique elements from the list.
.SH EXAMPLES
.EX
-assert [10, 20, 10, 10, 30].unique() == [10, 20, 30]
+assert [10, 20, 10, 10, 30].unique() == {10, 20, 30}
.EE
diff --git a/man/man3/tomo-Path.expand_home.3 b/man/man3/tomo-Path.expand_home.3
index 5dcf6a77..7114b65b 100644
--- a/man/man3/tomo-Path.expand_home.3
+++ b/man/man3/tomo-Path.expand_home.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH Path.expand_home 3 2025-05-17 "Tomo man-pages"
+.TH Path.expand_home 3 2025-10-11 "Tomo man-pages"
.SH NAME
Path.expand_home \- expand ~ to $HOME
.SH LIBRARY
@@ -29,8 +29,8 @@ If the path does not start with a `~`, then return it unmodified. Otherwise, rep
.SH EXAMPLES
.EX
->> (~/foo).expand_home() # Assume current user is 'user'
-= /home/user/foo
->> (/foo).expand_home() # No change
-= /foo
+# Assume current user is 'user'
+assert (~/foo).expand_home() == (/home/user/foo)
+# No change
+assert (/foo).expand_home() == (/foo)
.EE
diff --git a/man/man3/tomo-Text.from_codepoint_names.3 b/man/man3/tomo-Text.from_codepoint_names.3
index 4d9dc59d..4a1f9f56 100644
--- a/man/man3/tomo-Text.from_codepoint_names.3
+++ b/man/man3/tomo-Text.from_codepoint_names.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH Text.from_codepoint_names 3 2025-04-30 "Tomo man-pages"
+.TH Text.from_codepoint_names 3 2025-10-11 "Tomo man-pages"
.SH NAME
Text.from_codepoint_names \- convert list of unicode codepoint names to text
.SH LIBRARY
@@ -32,10 +32,10 @@ The text will be normalized, so the resulting text's codepoints may not exactly
.SH EXAMPLES
.EX
->> Text.from_codepoint_names([
-"LATIN CAPITAL LETTER A WITH RING ABOVE",
-"LATIN SMALL LETTER K",
-"LATIN SMALL LETTER E",
+text := Text.from_codepoint_names([
+ "LATIN CAPITAL LETTER A WITH RING ABOVE",
+ "LATIN SMALL LETTER K",
+ "LATIN SMALL LETTER E",
]
-= "Åke"
+assert text == "Åke"
.EE
diff --git a/man/man3/tomo-Text.translate.3 b/man/man3/tomo-Text.translate.3
index e8b36ec4..8cfeb3f7 100644
--- a/man/man3/tomo-Text.translate.3
+++ b/man/man3/tomo-Text.translate.3
@@ -2,14 +2,14 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH Text.translate 3 2025-04-30 "Tomo man-pages"
+.TH Text.translate 3 2025-10-11 "Tomo man-pages"
.SH NAME
Text.translate \- perform multiple replacements
.SH LIBRARY
Tomo Standard Library
.SH SYNOPSIS
.nf
-.BI Text.translate\ :\ func(text:\ Text,\ translations:\ {Text=Text}\ ->\ Text)
+.BI Text.translate\ :\ func(text:\ Text,\ translations:\ {Text:Text}\ ->\ Text)
.fi
.SH DESCRIPTION
Takes a table mapping target texts to their replacements and performs all the replacements in the table on the whole text. At each position, the first matching replacement is applied and the matching moves on to *after* the replacement text, so replacement text is not recursively modified. See Text.replace() for more information about replacement behavior.
@@ -23,19 +23,19 @@ lb lb lbx lb
l l l l.
Name Type Description Default
text Text The text to be translated. -
-translations {Text=Text} A table mapping from target text to its replacement. -
+translations {Text:Text} A table mapping from target text to its replacement. -
.TE
.SH RETURN
The text with all occurrences of the targets replaced with their corresponding replacement text.
.SH EXAMPLES
.EX
->> "A <tag> & an amperand".translate({
- "&" = "&amp;",
- "<" = "&lt;",
- ">" = "&gt;",
- '"" = "&quot",
- "'" = "&#39;",
+text := "A <tag> & an amperand".translate({
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"": "&quot",
+ "'": "&#39;",
})
-= "A &lt;tag&gt; &amp; an ampersand"
+assert text == "A &lt;tag&gt; &amp; an ampersand"
.EE
diff --git a/man/man3/tomo-getenv.3 b/man/man3/tomo-getenv.3
index e06e35ff..84bef6be 100644
--- a/man/man3/tomo-getenv.3
+++ b/man/man3/tomo-getenv.3
@@ -2,7 +2,7 @@
.\" Copyright (c) 2025 Bruce Hill
.\" All rights reserved.
.\"
-.TH getenv 3 2025-05-17 "Tomo man-pages"
+.TH getenv 3 2025-10-11 "Tomo man-pages"
.SH NAME
getenv \- get an environment variable
.SH LIBRARY
@@ -29,6 +29,6 @@ If set, the environment variable's value, otherwise, `none`.
.SH EXAMPLES
.EX
->> getenv("TERM")
-= "xterm-256color"?
+assert getenv("TERM") == "xterm-256color"
+assert getenv("not_a_variable") == none
.EE
diff --git a/src/compile/lists.c b/src/compile/lists.c
index d9fb46a3..bb94eb1d 100644
--- a/src/compile/lists.c
+++ b/src/compile/lists.c
@@ -253,7 +253,7 @@ Text_t compile_list_method_call(env_t *env, ast_t *ast) {
} else if (streq(call->name, "unique")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
(void)compile_arguments(env, ast, NULL, call->args);
- return Texts("Table$from_entries(", self, ", Table$info(", compile_type_info(item_t), ", &Void$info)).entries");
+ return Texts("Table$from_entries(", self, ", Table$info(", compile_type_info(item_t), ", &Empty$$info))");
} else if (streq(call->name, "pop")) {
EXPECT_POINTER();
arg_t *arg_spec = new (arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, "-1"));
diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c
index fdd85b56..3c78b770 100644
--- a/src/stdlib/tables.c
+++ b/src/stdlib/tables.c
@@ -390,8 +390,10 @@ PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_
void *x_key = x->entries.data + i * x->entries.stride;
void *y_value = Table$get_raw(*y, x_key, type);
if (!y_value) return false;
- void *x_value = x_key + offset;
- if (!generic_equal(y_value, x_value, value_type)) return false;
+ if (value_type->size > 0) {
+ void *x_value = x_key + offset;
+ if (!generic_equal(y_value, x_value, value_type)) return false;
+ }
}
return true;
}
@@ -439,7 +441,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type
void *y_value = key + value_offset(type);
void *x_value = Table$get_raw(*x, key, type);
- if (!x_value || !generic_equal(x_value, y_value, table.value)) {
+ if (!x_value || (table.value->size > 0 && !generic_equal(x_value, y_value, table.value))) {
if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) mismatched_key = key;
}
}
@@ -589,7 +591,7 @@ Table_t Table$intersection(Table_t a, Table_t b, const TypeInfo_t *type) {
void *key = GET_ENTRY(*t, i);
void *a_value = key + offset;
void *b_value = Table$get(b, key, type);
- if (b_value && generic_equal(a_value, b_value, type->TableInfo.value))
+ if (b_value && (type->TableInfo.value->size == 0 || generic_equal(a_value, b_value, type->TableInfo.value)))
Table$set(&result, key, a_value, type);
}
}
@@ -650,7 +652,8 @@ Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) {
void *key = GET_ENTRY(*t, i);
void *a_value = key + offset;
void *b_value = Table$get(b, key, type);
- if (!b_value || !generic_equal(a_value, b_value, type->TableInfo.value))
+ if (!b_value
+ || (type->TableInfo.value->size > 0 && !generic_equal(a_value, b_value, type->TableInfo.value)))
Table$set(&result, key, a_value, type);
}
}
diff --git a/src/typecheck.c b/src/typecheck.c
index 9342f069..67fb1168 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -969,7 +969,8 @@ type_t *get_type(env_t *env, ast_t *ast) {
else if (streq(call->name, "sort")) return Type(VoidType);
else if (streq(call->name, "sorted")) return self_value_t;
else if (streq(call->name, "to")) return self_value_t;
- else if (streq(call->name, "unique")) return Type(ListType, .item_type = item_type);
+ else if (streq(call->name, "unique"))
+ return Type(TableType, .key_type = item_type, .value_type = EMPTY_TYPE);
else code_err(ast, "There is no '", call->name, "' method for lists");
}
case TableType: {
diff --git a/test/lists.tm b/test/lists.tm
index 176c3d6d..4e9f769b 100644
--- a/test/lists.tm
+++ b/test/lists.tm
@@ -144,4 +144,4 @@ func main()
assert nums[] == []
assert nums.pop() == none
- assert [1,2,1,2,3].unique() == [1,2,3]
+ assert [1,2,1,2,3].unique() == {1,2,3}