From 52e50e58c6674560056a4dcb787099d739284b02 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 6 Apr 2025 16:34:23 -0400 Subject: Change Set syntax from {x} to |x| --- docs/sets.md | 89 +++++++++++++++++++++---------------------- examples/learnxiny.tm | 11 +++--- examples/log/log.tm | 2 +- examples/tomodeps/tomodeps.tm | 30 +++++++-------- src/parse.c | 13 +++---- src/stdlib/tables.c | 11 ++---- src/types.c | 4 +- test/enums.tm | 2 +- test/optionals.tm | 4 +- test/serialization.tm | 4 +- test/sets.tm | 31 ++++++++------- test/structs.tm | 4 +- test/tables.tm | 4 +- 13 files changed, 102 insertions(+), 107 deletions(-) diff --git a/docs/sets.md b/docs/sets.md index 62351ed5..88e47e98 100644 --- a/docs/sets.md +++ b/docs/sets.md @@ -4,37 +4,36 @@ Sets represent an unordered collection of unique elements. These are implemented using hash tables. ```tomo -a := {10, 20, 30} -b := {20, 30} +a := |10, 20, 30| +b := |20, 30| >> a.overlap(b) -= {20} += |20| ``` ## Syntax -Sets are written using `{...}` curly braces with comma-separated items: +Sets are written using `|...|` vertical pipes with comma-separated items: ```tomo -nums := {10, 20, 30} +nums := |10, 20, 30| ``` -Empty sets must specify the set type explicitly and use `{/}` for an empty set -(because `{}` is an empty table). +Empty sets must specify the set type explicitly: ```tomo -empty : {Int} = {/} +empty : |Int| = || ``` -For type annotations, a set that holds items with type `T` is written as `{T}`. +For type annotations, a set that holds items with type `T` is written as `|T|`. ### Comprehensions Similar to arrays, sets can use comprehensions: ```tomo -set := {10*i for i in 10} -set2 := {10*i for i in 10 if i mod 2 == 0} -set3 := {-10, 10*i for i in 10} +set := |10*i for i in 10| +set2 := |10*i for i in 10 if i mod 2 == 0| +set3 := |-10, 10*i for i in 10| ``` ## Accessing Items @@ -44,7 +43,7 @@ Sets internally store their items in an array, which you can access with the view: ```tomo -set := {10, 20, 30} +set := |10, 20, 30| >> set.items = [10, 20, 30] ``` @@ -54,7 +53,7 @@ set := {10, 20, 30} Set length can be accessed by the `.length` field: ```tomo ->> {10, 20, 30}.length +>> |10, 20, 30|.length = 3 ``` @@ -76,23 +75,23 @@ iterating over any of the new values. ## Set Methods -- [`func add(set:{T}, item: T -> Void)`](#add) -- [`func add_all(set:@{T}, items: [T] -> Void)`](#add_all) -- [`func clear(set:@{T} -> Void)`](#clear) -- [`func has(set:{T}, item:T -> Bool)`](#has) -- [`func (set: {T}, other: {T}, strict: Bool = no -> Bool)`](#is_subset_of) -- [`func is_superset_of(set:{T}, other: {T}, strict: Bool = no -> Bool)`](#is_superset_of) -- [`func overlap(set:{T}, other: {T} -> {T})`](#overlap) -- [`func remove(set:@{T}, item: T -> Void)`](#remove) -- [`func remove_all(set:@{T}, items: [T] -> Void)`](#remove_all) -- [`func with(set:{T}, other: {T} -> {T})`](#with) -- [`func without(set:{T}, other: {T} -> {T})`](#without) +- [`func add(set:|T|, item: T -> Void)`](#add) +- [`func add_all(set:@|T|, items: [T] -> Void)`](#add_all) +- [`func clear(set:@|T| -> Void)`](#clear) +- [`func has(set:|T|, item:T -> Bool)`](#has) +- [`func (set: |T|, other: |T|, strict: Bool = no -> Bool)`](#is_subset_of) +- [`func is_superset_of(set:|T|, other: |T|, strict: Bool = no -> Bool)`](#is_superset_of) +- [`func overlap(set:|T|, other: |T| -> |T|)`](#overlap) +- [`func remove(set:@|T|, item: T -> Void)`](#remove) +- [`func remove_all(set:@|T|, items: [T] -> Void)`](#remove_all) +- [`func with(set:|T|, other: |T| -> |T|)`](#with) +- [`func without(set:|T|, other: |T| -> |T|)`](#without) ### `add` Adds an item to the set. ```tomo -func add(set:{T}, item: T -> Void) +func add(set:|T|, item: T -> Void) ``` - `set`: The mutable reference to the set. @@ -112,7 +111,7 @@ Nothing. Adds multiple items to the set. ```tomo -func add_all(set:@{T}, items: [T] -> Void) +func add_all(set:@|T|, items: [T] -> Void) ``` - `set`: The mutable reference to the set. @@ -132,7 +131,7 @@ Nothing. Removes all items from the set. ```tomo -func clear(set:@{T} -> Void) +func clear(set:@|T| -> Void) ``` - `set`: The mutable reference to the set. @@ -151,7 +150,7 @@ Nothing. Checks if the set contains a specified item. ```tomo -func has(set:{T}, item:T -> Bool) +func has(set:|T|, item:T -> Bool) ``` - `set`: The set to check. @@ -162,7 +161,7 @@ func has(set:{T}, item:T -> Bool) **Example:** ```tomo ->> {10, 20}.has(20) +>> |10, 20|.has(20) = yes ``` @@ -172,7 +171,7 @@ func has(set:{T}, item:T -> Bool) Checks if the set is a subset of another set. ```tomo -func (set: {T}, other: {T}, strict: Bool = no -> Bool) +func (set: |T|, other: |T|, strict: Bool = no -> Bool) ``` - `set`: The set to check. @@ -184,7 +183,7 @@ func (set: {T}, other: {T}, strict: Bool = no -> Bool) **Example:** ```tomo ->> {1, 2}.is_subset_of({1, 2, 3}) +>> |1, 2|.is_subset_of(|1, 2, 3|) = yes ``` @@ -194,7 +193,7 @@ func (set: {T}, other: {T}, strict: Bool = no -> Bool) Checks if the set is a superset of another set. ```tomo -func is_superset_of(set:{T}, other: {T}, strict: Bool = no -> Bool) +func is_superset_of(set:|T|, other: |T|, strict: Bool = no -> Bool) ``` - `set`: The set to check. @@ -206,14 +205,14 @@ func is_superset_of(set:{T}, other: {T}, strict: Bool = no -> Bool) **Example:** ```tomo ->> {1, 2, 3}.is_superset_of({1, 2}) +>> |1, 2, 3|.is_superset_of(|1, 2|) = yes ``` ### `overlap` Creates a new set with items that are in both the original set and another set. ```tomo -func overlap(set:{T}, other: {T} -> {T}) +func overlap(set:|T|, other: |T| -> |T|) ``` - `set`: The original set. @@ -224,8 +223,8 @@ A new set containing only items present in both sets. **Example:** ```tomo ->> {1, 2}.overlap({2, 3}) -= {2} +>> |1, 2|.overlap(|2, 3|) += |2| ``` --- @@ -234,7 +233,7 @@ A new set containing only items present in both sets. Removes an item from the set. ```tomo -func remove(set:@{T}, item: T -> Void) +func remove(set:@|T|, item: T -> Void) ``` - `set`: The mutable reference to the set. @@ -254,7 +253,7 @@ Nothing. Removes multiple items from the set. ```tomo -func remove_all(set:@{T}, items: [T] -> Void) +func remove_all(set:@|T|, items: [T] -> Void) ``` - `set`: The mutable reference to the set. @@ -274,7 +273,7 @@ Nothing. Creates a new set that is the union of the original set and another set. ```tomo -func with(set:{T}, other: {T} -> {T}) +func with(set:|T|, other: |T| -> |T|) ``` - `set`: The original set. @@ -285,8 +284,8 @@ A new set containing all items from both sets. **Example:** ```tomo ->> {1, 2}.with({2, 3}) -= {1, 2, 3} +>> |1, 2|.with(|2, 3|) += |1, 2, 3| ``` --- @@ -295,7 +294,7 @@ A new set containing all items from both sets. Creates a new set with items from the original set but without items from another set. ```tomo -func without(set:{T}, other: {T} -> {T}) +func without(set:|T|, other: |T| -> |T|) ``` - `set`: The original set. @@ -306,6 +305,6 @@ A new set containing items from the original set excluding those in the other se **Example:** ```tomo ->> {1, 2}.without({2, 3}) -= {1} +>> |1, 2|.without(|2, 3|) += |1| ``` diff --git a/examples/learnxiny.tm b/examples/learnxiny.tm index 6a3b7e21..74cba5df 100644 --- a/examples/learnxiny.tm +++ b/examples/learnxiny.tm @@ -159,20 +159,20 @@ func main(): # Sets are similar to tables, but they represent an unordered collection of # unique values: - set := {10, 20, 30} + set := |10, 20, 30| >> set.has(20) = yes >> set.has(999) = no # You can do some operations on sets: - other_set := {30, 40, 50} + other_set := |30, 40, 50| >> set.with(other_set) - = {10, 20, 30, 40, 50} + = |10, 20, 30, 40, 50| >> set.without(other_set) - = {10, 20} + = |10, 20| >> set.overlap(other_set) - = {30} + = |30| # So far, the datastructures that have been discussed are all *immutable*, # meaning you can't add, remove, or change their contents. If you want to @@ -241,6 +241,7 @@ func takes_many_types( text_aka_string:Text, array_of_ints:[Int], table_of_text_to_bools:{Text=Bool}, + set_of_ints:|Int|, pointer_to_mutable_array_of_ints:@[Int], optional_int:Int?, function_from_int_to_text:func(x:Int -> Text), diff --git a/examples/log/log.tm b/examples/log/log.tm index 7375d5f6..047398b0 100644 --- a/examples/log/log.tm +++ b/examples/log/log.tm @@ -3,7 +3,7 @@ use timestamp_format := CString("%F %T") -logfiles : @{Path} = @{/} +logfiles : @|Path| = @|| func _timestamp(->Text): c_str := inline C:CString { diff --git a/examples/tomodeps/tomodeps.tm b/examples/tomodeps/tomodeps.tm index dd7bec10..66bb74bd 100644 --- a/examples/tomodeps/tomodeps.tm +++ b/examples/tomodeps/tomodeps.tm @@ -11,12 +11,12 @@ _HELP := " enum Dependency(File(path:Path), Module(name:Text)) -func _get_file_dependencies(file:Path -> {Dependency}): +func _get_file_dependencies(file:Path -> |Dependency|): if not file.is_file(): say("Could not read file: $file") - return {/} + return || - deps : @{Dependency} = @{/} + deps : @|Dependency| = @|| if lines := file.by_line(): for line in lines: if line.matches_pattern($Pat/use {..}.tm/): @@ -27,18 +27,18 @@ func _get_file_dependencies(file:Path -> {Dependency}): deps.add(Dependency.Module(module_name)) return deps[] -func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency={Dependency}}): +func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency=|Dependency|}): return if dependencies.has(dep) - dependencies[dep] = {/} # Placeholder + dependencies[dep] = || # Placeholder dep_deps := when dep is File(path): _get_file_dependencies(path) is Module(module): dir := (~/.local/share/tomo/installed/$module) - module_deps : @{Dependency} = @{/} - visited : @{Path} = @{/} - unvisited := @{f.resolved() for f in dir.files() if f.extension() == ".tm"} + module_deps : @|Dependency| = @|| + visited : @|Path| = @|| + unvisited := @|f.resolved() for f in dir.files() if f.extension() == ".tm"| while unvisited.length > 0: file := unvisited.items[-1] unvisited.remove(file) @@ -57,8 +57,8 @@ func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency={Dependen for dep2 in dep_deps: _build_dependency_graph(dep2, dependencies) -func get_dependency_graph(dep:Dependency -> {Dependency={Dependency}}): - graph : @{Dependency={Dependency}} = @{} +func get_dependency_graph(dep:Dependency -> {Dependency=|Dependency|}): + graph : @{Dependency=|Dependency|} = @{} _build_dependency_graph(dep, graph) return graph @@ -72,7 +72,7 @@ func _printable_name(dep:Dependency -> Text): else: return "$(\x1b)[31;1m$(f) (not found)$(\x1b)[m" -func _draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}, already_printed:@{Dependency}, prefix="", is_last=yes): +func _draw_tree(dep:Dependency, dependencies:{Dependency=|Dependency|}, already_printed:@|Dependency|, prefix="", is_last=yes): if already_printed.has(dep): say(prefix ++ (if is_last: "└── " else: "├── ") ++ _printable_name(dep) ++ " $\x1b[2m(recursive)$\x1b[m") return @@ -82,16 +82,16 @@ func _draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}, already_ child_prefix := prefix ++ (if is_last: " " else: "│ ") - children := dependencies[dep] or {/} + children := dependencies[dep] or || for i,child in children.items: is_child_last := (i == children.length) _draw_tree(child, dependencies, already_printed, child_prefix, is_child_last) -func draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}): - printed : @{Dependency} = @{/} +func draw_tree(dep:Dependency, dependencies:{Dependency=|Dependency|}): + printed : @|Dependency| = @|| say(_printable_name(dep)) printed.add(dep) - deps := dependencies[dep] or {/} + deps := dependencies[dep] or || for i,child in deps.items: is_child_last := (i == deps.length) _draw_tree(child, dependencies, already_printed=printed, is_last=is_child_last) diff --git a/src/parse.c b/src/parse.c index 0f76243d..b0f9206d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -520,14 +520,13 @@ type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) { type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos) { const char *start = pos; - if (!match(&pos, "{")) return NULL; + if (!match(&pos, "|")) return NULL; whitespace(&pos); type_ast_t *item_type = parse_type(ctx, pos); if (!item_type) return NULL; pos = item_type->end; whitespace(&pos); - if (match(&pos, ",")) return NULL; - expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this set type"); + expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set type"); return NewTypeAST(ctx->file, start, pos, SetTypeAST, .item=item_type); } @@ -706,7 +705,6 @@ PARSER(parse_array) { PARSER(parse_table) { const char *start = pos; - if (match(&pos, "{/}")) return NULL; if (!match(&pos, "{")) return NULL; whitespace(&pos); @@ -768,10 +766,10 @@ PARSER(parse_table) { PARSER(parse_set) { const char *start = pos; - if (match(&pos, "{/}")) + if (match(&pos, "||")) return NewAST(ctx->file, start, pos, Set); - if (!match(&pos, "{")) return NULL; + if (!match(&pos, "|")) return NULL; whitespace(&pos); @@ -780,7 +778,6 @@ PARSER(parse_set) { ast_t *item = optional(ctx, &pos, parse_extended_expr); if (!item) break; whitespace(&pos); - if (match(&pos, "=")) return NULL; ast_t *suffixed = parse_comprehension_suffix(ctx, item); while (suffixed) { item = suffixed; @@ -795,7 +792,7 @@ PARSER(parse_set) { REVERSE_LIST(items); whitespace(&pos); - expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this set"); + expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set"); return NewAST(ctx->file, start, pos, Set, .items=items); } diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index 71b9c7f4..d59bc113 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -588,13 +588,13 @@ public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *ty Text("}")); else return Text$concat( - Text("{"), + Text("|"), generic_as_text(NULL, false, table.key), - Text("}")); + Text("|")); } int64_t val_off = (int64_t)value_offset(type); - Text_t text = Text("{"); + Text_t text = table.value == &Void$info ? Text("|") : Text("{"); for (int64_t i = 0, length = Table$length(*t); i < length; i++) { if (i > 0) text = Text$concat(text, Text(", ")); @@ -604,14 +604,11 @@ public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *ty text = Text$concat(text, Text("="), generic_as_text(entry + val_off, colorize, table.value)); } - if (table.value == &Void$info) - text = Text$concat(text, Text("/")); - if (t->fallback) { text = Text$concat(text, Text("; fallback="), Table$as_text(t->fallback, colorize, type)); } - text = Text$concat(text, Text("}")); + text = Text$concat(text, table.value == &Void$info ? Text("|") : Text("}")); return text; } diff --git a/src/types.c b/src/types.c index 29963f76..0b69a8c4 100644 --- a/src/types.c +++ b/src/types.c @@ -370,9 +370,7 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed) if (actual->tag == ArrayType && needed->tag == ArrayType && Match(actual, ArrayType)->item_type == NULL) return true; // [] -> [T] if (actual->tag == SetType && needed->tag == SetType && Match(actual, SetType)->item_type == NULL) - return true; // {/} -> {T} - if (actual->tag == TableType && needed->tag == SetType && Match(actual, TableType)->key_type == NULL && Match(actual, TableType)->value_type == NULL) - return true; // {} -> {T} + return true; // || -> |T| if (actual->tag == TableType && needed->tag == TableType && Match(actual, TableType)->key_type == NULL && Match(actual, TableType)->value_type == NULL) return true; // {} -> {K=V} diff --git a/test/enums.tm b/test/enums.tm index a11f95f9..cbea69f5 100644 --- a/test/enums.tm +++ b/test/enums.tm @@ -42,7 +42,7 @@ func main(): = yes >> x := Foo.One(123) - >> t := {x} + >> t := |x| >> t.has(x) = yes >> t.has(Foo.Zero) diff --git a/test/optionals.tm b/test/optionals.tm index bf3e1633..40512557 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -245,8 +245,8 @@ func main(): = no >> (5? == 5?) = yes - >> nones : {Int?} = {none, none} - >> also_nones : {Int?} = {none} + >> nones : |Int?| = |none, none| + >> also_nones : |Int?| = |none| >> nones == also_nones >> [5?, none, none, 6?].sorted() = [none, none, 5, 6] diff --git a/test/serialization.tm b/test/serialization.tm index b3ccc67a..a09cf2f9 100644 --- a/test/serialization.tm +++ b/test/serialization.tm @@ -76,9 +76,9 @@ func main(): = yes do: - >> obj := {10, 20, 30} + >> obj := |10, 20, 30| >> bytes := obj.serialized() - >> deserialize(bytes -> {Int}) == obj + >> deserialize(bytes -> |Int|) == obj = yes do: diff --git a/test/sets.tm b/test/sets.tm index 5179947e..058c1218 100644 --- a/test/sets.tm +++ b/test/sets.tm @@ -1,39 +1,42 @@ func main(): - >> t1 := @{10, 20, 30, 10} - = @{10, 20, 30} + >> t1 := @|10, 20, 30, 10| + = @|10, 20, 30| >> t1.has(10) = yes >> t1.has(-999) = no - >> t2 := {30, 40} + >> t2 := |30, 40| >> t1.with(t2) - >> {10, 20, 30, 40} + >> |10, 20, 30, 40| >> t1.without(t2) - >> {10, 20} + >> |10, 20| >> t1.overlap(t2) - >> {30} + >> |30| - >> {1,2}.is_subset_of({2,3}) + >> |1,2|.is_subset_of(|2,3|) = no - >> {1,2}.is_subset_of({1,2,3}) + >> |1,2|.is_subset_of(|1,2,3|) = yes - >> {1,2}.is_subset_of({1,2}) + >> |1,2|.is_subset_of(|1,2|) = yes - >> {1,2}.is_subset_of({1,2}, strict=yes) + >> |1,2|.is_subset_of(|1,2|, strict=yes) = no >> t1.add_all(t2) >> t1 - = @{10, 20, 30, 40} + = @|10, 20, 30, 40| >> t1.remove_all(t2) >> t1 - = @{10, 20} + = @|10, 20| - >> {3, i for i in 5} - = {3, 1, 2, 4, 5} + >> |3, i for i in 5| + = |3, 1, 2, 4, 5| + + >> empty : |Int| = || + = || diff --git a/test/structs.tm b/test/structs.tm index cf7b6a1c..2b1ff910 100644 --- a/test/structs.tm +++ b/test/structs.tm @@ -32,7 +32,7 @@ func test_metamethods(): >> x < Pair(11, 20) = yes - >> set := {x} + >> set := |x| >> set.has(x) = yes >> set.has(y) @@ -49,7 +49,7 @@ func test_mixed(): = no >> x < Mixed(11, "Hello") = yes - >> set := {x} + >> set := |x| >> set.has(x) = yes >> set.has(y) diff --git a/test/tables.tm b/test/tables.tm index a5f51520..41d041eb 100644 --- a/test/tables.tm +++ b/test/tables.tm @@ -99,8 +99,8 @@ func main(): >> ints : [{Int=Int}] = [{}, {0=0}, {99=99}, {1=1, 2=2, 3=3}, {1=1, 99=99, 3=3}, {1=1, 2=-99, 3=3}, {1=1, 99=-99, 3=4}].sorted() = [{}, {0=0}, {1=1, 2=-99, 3=3}, {1=1, 2=2, 3=3}, {1=1, 99=99, 3=3}, {1=1, 99=-99, 3=4}, {99=99}] - >> other_ints : [{Int}] = [{/}, {1}, {2}, {99}, {0, 3}, {1, 2}, {99}].sorted() - = [{/}, {0, 3}, {1}, {1, 2}, {2}, {99}, {99}] + >> other_ints : [|Int|] = [||, |1|, |2|, |99|, |0, 3|, |1, 2|, |99|].sorted() + = [||, |0, 3|, |1|, |1, 2|, |2|, |99|, |99|] do: # Default values: -- cgit v1.2.3