From 4b3e4ae15e8e66faf27a810337bfe6d65f8a2827 Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Tue, 9 Jul 2024 10:12:23 +0100 Subject: [PATCH] Rename `Map` to `Dictionary` and `Set` to `Hashset`. (#10474) - Rename `Map` to `Dictionary`. - Rename `Set` to `Hashset`. - Add a deprecated place holder for the static method of `Map`. --- CHANGELOG.md | 2 + .../lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso | 6 +- .../lib/Standard/Base/0.0.0-dev/src/Any.enso | 4 +- .../lib/Standard/Base/0.0.0-dev/src/Data.enso | 4 +- .../Base/0.0.0-dev/src/Data/Dictionary.enso | 425 ++++++++++++ .../0.0.0-dev/src/Data/Filter_Condition.enso | 6 +- .../src/Data/{Set.enso => Hashset.enso} | 70 +- .../Base/0.0.0-dev/src/Data/Json.enso | 14 +- .../0.0.0-dev/src/Data/Json/Extensions.enso | 10 +- .../Standard/Base/0.0.0-dev/src/Data/Map.enso | 443 +----------- .../Base/0.0.0-dev/src/Data/Text/Regex.enso | 27 +- .../0.0.0-dev/src/Data/Text/Regex/Match.enso | 13 +- .../Standard/Base/0.0.0-dev/src/Data/XML.enso | 16 +- .../0.0.0-dev/src/Enso_Cloud/Enso_Secret.enso | 4 +- .../Internal/Enso_File_Helpers.enso | 8 +- .../Internal/Existing_Enso_Asset.enso | 4 +- .../src/Enso_Cloud/Internal/Utils.enso | 6 +- .../src/Internal/Array_Like_Helpers.enso | 6 +- .../lib/Standard/Base/0.0.0-dev/src/Main.enso | 3 +- .../Base/0.0.0-dev/src/Network/HTTP.enso | 18 +- .../0.0.0-dev/src/Network/HTTP/Request.enso | 8 +- .../src/Network/HTTP/Request_Body.enso | 4 +- .../0.0.0-dev/src/Network/HTTP/Response.enso | 2 +- .../Standard/Base/0.0.0-dev/src/Random.enso | 2 - .../Standard/Base/0.0.0-dev/src/Warning.enso | 2 +- .../0.0.0-dev/src/Connection/Connection.enso | 4 +- .../Database/0.0.0-dev/src/DB_Table.enso | 44 +- .../src/Internal/Base_Generator.enso | 21 +- .../Internal/Common/Database_Join_Helper.enso | 7 +- .../Internal/Postgres/Postgres_Dialect.enso | 6 +- .../Postgres/Postgres_Type_Mapping.enso | 4 +- .../src/Internal/SQLite/SQLite_Dialect.enso | 6 +- .../Internal/SQLite/SQLite_Type_Mapping.enso | 12 +- .../0.0.0-dev/src/Internal/Upload_Table.enso | 16 +- .../Standard/Examples/0.0.0-dev/src/Main.enso | 6 +- .../src/Internal/Snowflake_Dialect.enso | 6 +- .../src/Internal/Snowflake_Type_Mapping.enso | 4 +- .../Standard/Table/0.0.0-dev/src/Column.enso | 2 +- .../Conversions/Convertible_To_Columns.enso | 12 +- .../src/Conversions/Convertible_To_Rows.enso | 2 +- .../Standard/Table/0.0.0-dev/src/Errors.enso | 2 +- .../src/Internal/Expand_Objects_Helpers.enso | 29 +- .../Table/0.0.0-dev/src/Internal/Fan_Out.enso | 10 +- .../src/Internal/Lookup_Helpers.enso | 4 +- .../src/Internal/Replace_Helpers.enso | 10 +- .../src/Internal/Split_Tokenize.enso | 2 +- .../0.0.0-dev/src/Internal/Table_Helpers.enso | 36 +- .../src/Internal/Unique_Name_Strategy.enso | 4 +- .../Table/0.0.0-dev/src/Match_Columns.enso | 4 +- .../lib/Standard/Table/0.0.0-dev/src/Row.enso | 8 +- .../Standard/Table/0.0.0-dev/src/Table.enso | 55 +- .../Test/0.0.0-dev/src/Test_Reporter.enso | 2 +- .../0.0.0-dev/src/Scatter_Plot.enso | 2 +- .../0.0.0-dev/src/Table/Visualization.enso | 20 +- .../test/ConversionMethodTests.java | 8 +- .../enso/interpreter/test/MetaObjectTest.java | 132 ++-- .../interpreter/test/ValuesGenerator.java | 44 +- .../node/callable/InvokeConversionNode.java | 5 +- .../node/callable/InvokeMethodNode.java | 2 +- .../interpreter/runtime/builtin/Builtins.java | 8 +- .../runtime/data/hash/EnsoHashMap.java | 6 +- .../data/hash/HashMapContainsKeyNode.java | 2 +- .../runtime/data/hash/HashMapGetNode.java | 4 +- .../runtime/data/hash/HashMapInsertNode.java | 2 +- .../runtime/data/hash/HashMapRemoveNode.java | 2 +- .../runtime/data/hash/HashMapSizeNode.java | 2 +- .../runtime/data/hash/HashMapToTextNode.java | 2 +- .../data/hash/HashMapToVectorNode.java | 2 +- .../runtime/library/dispatch/TypeOfNode.java | 2 +- test/AWS_Tests/src/S3_Spec.enso | 2 +- test/Base_Tests/src/Data/Dictionary_Spec.enso | 633 +++++++++++++++++ .../Data/{Set_Spec.enso => Hashset_Spec.enso} | 49 +- test/Base_Tests/src/Data/Json_Spec.enso | 8 +- test/Base_Tests/src/Data/Map_Spec.enso | 637 ------------------ test/Base_Tests/src/Data/Text/Regex_Spec.enso | 2 +- test/Base_Tests/src/Data/XML/XML_Spec.enso | 4 +- test/Base_Tests/src/Main.enso | 8 +- .../src/Network/Http/Request_Spec.enso | 2 +- test/Base_Tests/src/Network/Http_Spec.enso | 4 +- test/Benchmarks/src/Collections.enso | 2 +- test/Benchmarks/src/Map/Hash_Map.enso | 4 +- test/Examples_Tests/src/Examples_Spec.enso | 4 +- test/Snowflake_Tests/src/Snowflake_Spec.enso | 4 +- .../Column_Operations_Spec.enso | 2 +- .../Cross_Tab_Spec.enso | 2 +- .../Join/Replace_Spec.enso | 10 +- .../Map_To_Table_Spec.enso | 20 +- .../Select_Columns_Spec.enso | 34 +- .../src/Database/Postgres_Spec.enso | 6 +- .../Table_Tests/src/Database/SQLite_Spec.enso | 4 +- .../Types/SQLite_Type_Mapping_Spec.enso | 4 +- .../Table_Tests/src/Database/Upload_Spec.enso | 6 +- .../Helpers/Unique_Naming_Strategy_Spec.enso | 2 +- .../src/In_Memory/Table_Conversion_Spec.enso | 12 +- .../Table_Tests/src/In_Memory/Table_Spec.enso | 2 +- 95 files changed, 1585 insertions(+), 1552 deletions(-) create mode 100644 distribution/lib/Standard/Base/0.0.0-dev/src/Data/Dictionary.enso rename distribution/lib/Standard/Base/0.0.0-dev/src/Data/{Set.enso => Hashset.enso} (67%) create mode 100644 test/Base_Tests/src/Data/Dictionary_Spec.enso rename test/Base_Tests/src/Data/{Set_Spec.enso => Hashset_Spec.enso} (55%) delete mode 100644 test/Base_Tests/src/Data/Map_Spec.enso diff --git a/CHANGELOG.md b/CHANGELOG.md index 2737eabd722..73e8f9102e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,11 +14,13 @@ `Location.Right`.][10445] - [Renamed `Postgres_Details.Postgres` to `Postgres.Server`.][10466] - [Remove `First` and `Last` from namespace, use auto-scoped.][10467] +- [Rename `Map` to `Dictionary` and `Set` to `Hashset`.][10474] [10434]: https://github.com/enso-org/enso/pull/10434 [10445]: https://github.com/enso-org/enso/pull/10445 [10466]: https://github.com/enso-org/enso/pull/10466 [10467]: https://github.com/enso-org/enso/pull/10467 +[10474]: https://github.com/enso-org/enso/pull/10474 # Enso 2024.2 diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso index c0661cefba8..cf57e333916 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso @@ -96,11 +96,11 @@ read_bucket bucket prefix="" credentials:AWS_Credential=AWS_Credential.Default d - key: the key of the object. - credentials: AWS credentials. If not provided, the default credentials will be used. -head : Text -> Text -> AWS_Credential -> Map Text Any ! S3_Error +head : Text -> Text -> AWS_Credential -> Dictionary Text Any ! S3_Error head bucket key="" credentials:AWS_Credential=AWS_Credential.Default = response = raw_head bucket key credentials pairs = response.sdkFields.map f-> [f.memberName, f.getValueOrDefault response] - Map.from_vector pairs + Dictionary.from_vector pairs ## PRIVATE Gets the raw metadata of a bucket or object. @@ -109,7 +109,7 @@ head bucket key="" credentials:AWS_Credential=AWS_Credential.Default = - bucket: the name of the bucket. - key: the key of the object. - credentials: AWS credentials. -raw_head : Text -> Text -> AWS_Credential -> Map Text Any ! S3_Error +raw_head : Text -> Text -> AWS_Credential -> Dictionary Text Any ! S3_Error raw_head bucket key credentials = client = make_client_for_bucket bucket credentials case key == "" of diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso index 101ac05ab2f..d03f77d955c 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso @@ -392,8 +392,8 @@ type Any from Standard.Examples import Example_Error_Type example_map_error = - my_map = Map.empty - error = my_map.at "x" + my_dictionary = Dictionary.empty + error = my_dictionary.at "x" error.map_error (_ -> Example_Error_Type "x is missing") map_error : (Error -> Error) -> Any map_error self ~f = diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso index bcd2d0f41d0..e17fb60fa86 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso @@ -310,7 +310,7 @@ fetch (uri:(URI | Text)) (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector ( import Standard.Base.Data test_file = enso_project.data / "sample.png" - form_data = Map.from_vector [["key", "val"], ["a_file", test_file]] + form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]] response = Data.post url_post (Request_Body.Form_Data form_data) > Example @@ -318,7 +318,7 @@ fetch (uri:(URI | Text)) (method:HTTP_Method=HTTP_Method.Get) (headers:(Vector ( import Standard.Base.Data test_file = enso_project.data / "sample.txt" - form_data = Map.from_vector [["key", "val"], ["a_file", test_file]] + form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]] response = Data.post url_post (Request_Body.Form_Data form_data url_encoded=True) @uri Text_Input @response_format Data_Read_Helpers.format_widget_with_raw_response diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Dictionary.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Dictionary.enso new file mode 100644 index 00000000000..14fadddf374 --- /dev/null +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Dictionary.enso @@ -0,0 +1,425 @@ +import project.Any.Any +import project.Data.Numbers.Integer +import project.Data.Pair.Pair +import project.Data.Text.Text +import project.Data.Vector.Vector +import project.Error.Error +import project.Errors.Illegal_Argument.Illegal_Argument +import project.Errors.No_Such_Key.No_Such_Key +import project.Nothing.Nothing +import project.Panic.Panic +from project.Data.Boolean import Boolean, False, True +from project.Data.Text.Extensions import all + +## A key-value store. It is possible to use any type as keys and values and mix + them in one Dictionary. Keys are checked for equality based on their hash + code and `==` operator, which is both an internal part of Enso. Enso is + capable of computing a hash code, and checking for equality any objects that + can appear in Enso - primitives, Atoms, values coming from different + languages, etc. + + For keys that are not reflexive, like `Number.nan`, + [Same Value equality specification](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#same-value-zero_equality) + is used. This means that both `Number.nan` and types with comparators that + violate reflexivity (e.g. their `compare` method always returns `Nothing`) + can be used as keys in the Dictionary. + + A single key-value pair is called an *entry*. + + It is possible to pass a Dictionary created in Enso to foreign functions, + where it will be treated as appropriate map structures - in Python that is a + dictionary, and in JavaScript, it is a `Map`. And likewise, it is possible + to pass a foreign map into Enso, where it will be treated as a Dictionary. +@Builtin_Type +type Dictionary key value + ## PRIVATE + ADVANCED + Returns an empty dictionary. + empty : Dictionary + empty = @Builtin_Method "Dictionary.empty" + + ## PRIVATE + ADVANCED + Returns a single-element dictionary with the given key and value. + A Call to `Dictionary.singleton key value` is the same as a call to + `Dictionary.empty.insert key value`. + + Arguments: + - key: The key to to use for `value` in the dictionary. + - value: The value to store under 'key' in the dictionary. + + > Example + Create a single element dictionary storing the key "my_key" and the + value 2. + + example_singleton = Dictionary.singleton "my_key" 2 + singleton : Any -> Any -> Dictionary + singleton key value = Dictionary.empty.insert key value + + ## ALIAS dictionary, lookup table + GROUP Constants + ICON convert + Builds a dictionary from two Vectors. The first vector contains the keys, + and the second vector contains the values. The two vectors must be of the + same length. + + Arguments: + - keys: A vector of keys. + - values: A vector of values. + - error_on_duplicates: A flag which specifies if duplicate keys on the + input vector should result in an error. By default, set to `True`, + meaning that if two entries in the vector share the same key, an + `Illegal_Argument` error is raised. If set to `False`, the last entry + with a given key will be kept. + from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Dictionary ! Illegal_Argument + from_keys_and_values keys:Vector values:Vector error_on_duplicates:Boolean=True = + if keys.length != values.length then Error.throw (Illegal_Argument.Error "`Dictionary.from_keys_and_values` encountered two vectors of different lengths.") else + keys.fold_with_index Dictionary.empty current-> idx-> key-> + if error_on_duplicates.not || (current.contains_key key . not) then current.insert key (values.at idx) else + Error.throw (Illegal_Argument.Error "`Dictionary.from_keys_and_values` encountered duplicate key: "+key.to_display_text) + + ## ALIAS dictionary, lookup table + GROUP Constants + ICON convert + Builds a dictionary from a vector of key-value pairs, with each key-value + pair represented as a 2 element vector. + + Arguments: + - vec: A vector of key-value pairs (2 element vectors). + - error_on_duplicates: A flag which specifies if duplicate keys on the + input vector should result in an error. By default, set to `True`, + meaning that if two entries in the vector share the same key, an + `Illegal_Argument` error is raised. If set to `False`, the last entry + with a given key will be kept. + + > Example + Building a dictionary containing two key-value pairs. + + example_from_vector = Dictionary.from_vector [["A", 1], ["B", 2]] + from_vector : Vector Any -> Boolean -> Dictionary ! Illegal_Argument + from_vector vec error_on_duplicates=True = + vec.fold Dictionary.empty m-> el-> if el.length != 2 then Error.throw (Illegal_Argument.Error "`Dictionary.from_vector` encountered an invalid value. Each value in the vector has to be a key-value pair - it must have exactly 2 elements.") else + key = el.at 0 + value = el.at 1 + if error_on_duplicates.not || (m.contains_key key . not) then m.insert key value else + Error.throw (Illegal_Argument.Error "`Dictionary.from_vector` encountered duplicate key: "+key.to_display_text) + + ## GROUP Logical + ICON metadata + Returns True if the Dictionary is empty, i.e. does not have any entries. + is_empty : Boolean + is_empty self = self.size == 0 + + ## GROUP Logical + ICON metadata + Returns True if the Dictionary is not empty, i.e. has at least one entry. + not_empty : Boolean + not_empty self = self.is_empty.not + + ## GROUP Metadata + ICON metadata + Returns the number of entries in this dictionary. + size : Integer + size self = @Builtin_Method "Dictionary.size" + + ## GROUP Metadata + ICON metadata + Returns the number of entries in this dictionary. + length : Integer + length self = self.size + + ## GROUP Calculations + ICON row_add + Inserts a key-value mapping into this dictionary, overriding any existing + instance of `key` with the new `value`. + + Note that since the return type is also a `Dictionary`, multiple `insert` + calls can be chained, e.g., `dictionary.insert "A" 1 . insert "B" 2`. + + Due to the limitation of the current implementation, inserts with a + key that is already contained in the dictionary, or insert on a + dictionary instance that is re-used in other computations, have a linear + time complexity. For all the other cases, the time complexity of this + method is constant. + + Arguments: + - key: The key to insert the value for. + - value: The value to associate with the `key`. + + > Example + Insert the value "seven" into the dictionary for the key 7. + + import Standard.Examples + + example_insert = Examples.dictionary.insert 7 "seven" + insert : Any -> Any -> Dictionary + insert self key value = @Builtin_Method "Dictionary.insert" + + ## GROUP Selections + ICON table_clean + Removes an entry specified by the given key from this dictionary, and + returns a new dictionary without this entry. Throw `No_Such_Key.Error` if + `key` is not present. + + Arguments: + - key: The key to look up in the dictionary. + + > Example + Remove key "A" from a dictionary + + import Standard.Examples + + Examples.dictionary.remove "A" + remove : Any -> Dictionary ! No_Such_Key + remove self key = + Panic.catch Any (self.remove_builtin key) _-> + Error.throw (No_Such_Key.Error self key) + + ## GROUP Selections + ICON parse3 + Gets the value associated with `key` in this dictionary, or throws a + `No_Such_Key.Error` if `key` is not present. + + This method has a constant time complexity. + + Arguments: + - key: The key to look up in the dictionary. + + > Example + Looks up the value for the key "A" in a dictionary. + + import Standard.Examples + + example_at = Examples.dictionary.at "A" + at : Any -> Any ! No_Such_Key + at self key = self.get key (Error.throw (No_Such_Key.Error self key)) + + ## ICON parse3 + Gets the value associated with `key` in this dictionary, or returns + `if_missing` if it isn't present. + + This method has a constant time complexity. + + Arguments: + - key: The key to look up in the dictionary. + - if_missing: The value to use if the key isn't present. + + > Example + Get the value for the key 2 in a dictionary or instead return "zero" if it + isn't present. + + import Standard.Examples + + example_get = Examples.dictionary.get 2 "zero" + get : Any -> Any -> Any + get self key ~if_missing=Nothing = self.get_builtin key if_missing + + ## GROUP Logical + ICON preparation + Returns True iff the Dictionary contains the given `key`. + contains_key : Any -> Boolean + contains_key self key = @Builtin_Method "Dictionary.contains_key" + + ## GROUP Selections + ICON select_column + Returns an unsorted vector of all the keys in this Dictionary. + keys : Vector Any + keys self = self.to_vector.map pair-> pair.at 0 + + ## GROUP Selections + ICON select_column + Returns an unsorted vector of all the values in this Dictionary. + values : Vector Any + values self = self.to_vector.map pair-> pair.at 1 + + ## ICON column_add + Maps a function over each value in this dictionary. + + Arguments: + - function: The function to apply to each value in the dictionary, taking + a value and returning a value. + + > Example + Append "_word" to all values in the dictionary. + + import Standard.Examples + + example_map = Examples.dictionary.map (+ "_word") + map : (Any -> Any) -> Dictionary + map self function = + kv_func = _ -> function + self.map_with_key kv_func + + ## ICON column_add + Maps a function over each key-value pair in the dictionary, transforming + the value. + + Arguments: + - function: Function to apply to each key and value in the dictionary, + taking a key and a value and returning a value. + + > Example + Prepend the keys to the values in the dictionary. + + import Standard.Examples + + example_map_with_key = + Examples.dictionary.map_with_key (k -> v -> k.to_text + "-" + v) + map_with_key : (Any -> Any -> Any) -> Dictionary + map_with_key self function = + Dictionary.from_vector <| self.to_vector.map pair-> + key = pair.first + value = pair.last + [key, (function key value)] + + ## ICON column_add + Maps a function over each key in this dictionary. + + Arguments: + - function: The function to apply to each key in the dictionary, taking a + key and returning a new key. + + > Example + Doubling all keys in the dictionary. + + import Standard.Examples + + example_map_keys = Examples.dictionary.map_keys *2 + map_keys : (Any -> Any) -> Dictionary + map_keys self function = + trans_function = k -> v -> [function k, v] + self.transform trans_function + + ## ICON column_add + Transforms the map's keys and values to create a new dictionary. + + Arguments: + - function: The function used to transform the dictionary, taking a key + and a value and returning a pair of `[key, value]`. + + ! Error Conditions + - If multiple dictionary entries end up with duplicate keys after the + transformation, an `Illegal_Argument.Error` is thrown. + + > Example + Turn all keys into `Text` and append "_word" to the values in the + dictionary. + + import Standard.Examples + + example_transform = + Examples.dictionary.transform (k -> v -> [k.to_text, v + "_word"]) + transform : (Any -> Any -> [Any, Any]) -> Dictionary + transform self function = + func_pairs = p -> function (p.at 0) (p.at 1) + vec_transformed = self.to_vector.map func_pairs + new_dictionary = Dictionary.from_vector vec_transformed error_on_duplicates=True + new_dictionary.catch Illegal_Argument error-> + case error.message.starts_with "`Dictionary.from_vector` encountered duplicate key" of + True -> + new_message = error.message.replace "from_vector" "transform" + Error.throw (Illegal_Argument.Error new_message error.cause) + False -> new_dictionary + + ## ICON transform4 + Combines the values in the dictionary. + + Arguments: + - init: The initial value for the fold. + - function: A binary function to apply to pairs of values. + + > Example + Find the length of the longest word in the dictionary. + + import Standard.Examples + + example_fold = Examples.dictionary.fold 0 (l -> r -> l.max r.length) + fold : Any -> (Any -> Any -> Any) -> Any + fold self init function = self.values.fold init function + + ## ICON transform4 + Combines the key-value pairs in the dictionary. + + Arguments: + - init: The initial value for the fold. + - function: A function taking the left value, the current key, and the + current value, and combining them to yield a single value. + + > Example + Glue the values in the dictionary together with the keys. + + import Standard.Examples + + example_fold_with_key = + Examples.dictionary.fold_with_key "" (l -> k -> v -> l + k.to_text + v) + fold_with_key : Any -> (Any -> Any -> Any -> Any) -> Any + fold_with_key self init function = + self.to_vector.fold init acc-> pair-> + function acc pair.first pair.last + + ## PRIVATE + ADVANCED + Applies a function to each value in the dictionary. + + Arguments: + - function: The function to apply to each value in the dictionary, taking + a value and returning anything. + + This method does not return the results, so it is only useful for performing + computations with side-effects. + + If the function returns a dataflow error, the error is converted to a + panic and thrown immediately stopping further processing. + + > Example + Printing each value in the dictionary. + + import Standard.Examples + + example_each = Examples.dictionary.each IO.println + each : (Any -> Any) -> Nothing + each self function = + kv_func = _ -> function + self.each_with_key kv_func + + ## PRIVATE + ADVANCED + Applies a function to each key-value pair in the dictionary. + + Arguments: + - function: The function to apply to each key-value pair in the + dictionary, taking a key and a value and returning anything. + + This method does not return the results, so it is only useful for performing + computations with side-effects. + + > Example + Printing each key and value in the dictionary. + + import Standard.Examples + + example_each_with_key = Examples.dictionary.each_with_key k->v-> + IO.println k + IO.println v + each_with_key : (Any -> Any -> Any) -> Nothing + each_with_key self function = + self.to_vector.each pair-> + function pair.first pair.last + + ## GROUP Conversions + ICON convert + Returns an unsorted vector of key-value pairs (nested 2 element vectors). + `Dictionary.from_vector` method is an inverse method, so the following + expression is true for all dictionaries: + `Dictionary.from_vector dictionary.to_vector == dictionary`. + to_vector : Vector Any + to_vector self = @Builtin_Method "Dictionary.to_vector" + + ## PRIVATE + Returns a text representation of this Dictionary. + to_text : Text + to_text self = @Builtin_Method "Dictionary.to_text" + + ## PRIVATE + get_builtin : Any -> Any -> Any + get_builtin self key ~if_missing = @Builtin_Method "Dictionary.get_builtin" diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso index 528025b4844..2a637f9ff32 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Filter_Condition.enso @@ -1,7 +1,7 @@ import project.Any.Any +import project.Data.Hashset.Hashset import project.Data.Locale.Locale import project.Data.Numbers.Number -import project.Data.Set.Set import project.Data.Text.Case_Sensitivity.Case_Sensitivity import project.Data.Text.Regex.Regex import project.Data.Text.Text @@ -198,9 +198,7 @@ type Filter_Condition Like sql_pattern _ -> regex = sql_like_to_regex sql_pattern handle_nothing <| regex.matches - Is_In values _ -> - set = Set.from_vector values - set.contains + Is_In values _ -> Hashset.from_vector values . contains if self.action == Filter_Action.Keep then base else v -> (base v).not ## PRIVATE diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Set.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Hashset.enso similarity index 67% rename from distribution/lib/Standard/Base/0.0.0-dev/src/Data/Set.enso rename to distribution/lib/Standard/Base/0.0.0-dev/src/Data/Hashset.enso index 2fcd474f2cf..f73dffc6898 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Set.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Hashset.enso @@ -1,6 +1,6 @@ import project.Any.Any import project.Data.Array_Proxy.Array_Proxy -import project.Data.Map.Map +import project.Data.Dictionary.Dictionary import project.Data.Numbers.Integer import project.Data.Ordering.Comparable import project.Data.Ordering.Ordering @@ -13,9 +13,9 @@ from project.Data.Boolean import Boolean, False, True from project.Data.Text.Extensions import all ## An unordered collection of unique values. -type Set +type Hashset ## PRIVATE - Value (underlying_map : Map Any Nothing) + Value (underlying_dictionary : Dictionary Any Nothing) ## PRIVATE ADVANCED @@ -28,30 +28,30 @@ type Set occurrence of each duplicated element is retained in the set. If set to `True` it will raise an `Illegal_Argument` if duplicate elements are encountered. - from_vector : Vector Any -> Boolean -> Set ! Illegal_Argument + from_vector : Vector Any -> Boolean -> Hashset ! Illegal_Argument from_vector (vector : Vector) (error_on_duplicates : Boolean = False) = pairs_array = Array_Proxy.new vector.length (i-> [vector.at i, Nothing]) pairs = Vector.from_polyglot_array pairs_array - map = Map.from_vector pairs error_on_duplicates=error_on_duplicates - Set.Value map + dictionary = Dictionary.from_vector pairs error_on_duplicates=error_on_duplicates + Hashset.Value dictionary ## PRIVATE ADVANCED Constructs an empty set. - empty : Set - empty = Set.Value Map.empty + empty : Hashset + empty = Hashset.Value Dictionary.empty ## GROUP Conversions ICON convert Returns a vector containing all elements of this set. to_vector : Vector - to_vector self = self.underlying_map.keys + to_vector self = self.underlying_dictionary.keys ## GROUP Metadata ICON metadata Returns the number of elements in this set. size : Integer - size self = self.underlying_map.size + size self = self.underlying_dictionary.size ## GROUP Metadata ICON metadata @@ -63,19 +63,19 @@ type Set ICON metadata Checks if the set is empty. is_empty : Boolean - is_empty self = self.underlying_map.is_empty + is_empty self = self.underlying_dictionary.is_empty ## GROUP Logical ICON metadata Checks if the set is not empty. not_empty : Boolean - not_empty self = self.underlying_map.not_empty + not_empty self = self.underlying_dictionary.not_empty ## GROUP Logical ICON preparation Checks if this set contains a given value. contains : Any -> Boolean - contains self value = self.underlying_map.contains_key value + contains self value = self.underlying_dictionary.contains_key value ## GROUP Logical ICON preparation @@ -103,48 +103,48 @@ type Set GROUP Calculations ICON row_add Adds a value to this set. - insert : Any -> Set + insert : Any -> Hashset insert self value = - new_map = self.underlying_map.insert value Nothing - Set.Value new_map + dictionary = self.underlying_dictionary.insert value Nothing + Hashset.Value dictionary ## GROUP Calculations ICON union Creates a union of the two sets. - union : Set -> Set - union self (other : Set) = - start_map = self.underlying_map - new_map = other.to_vector.fold start_map m-> el-> m.insert el Nothing - Set.Value new_map + union : Hashset -> Hashset + union self (other : Hashset) = + start_dictionary = self.underlying_dictionary + dictionary = other.to_vector.fold start_dictionary m-> el-> m.insert el Nothing + Hashset.Value dictionary ## GROUP Calculations ICON join Creates an intersection of the two sets. - intersection : Set -> Set - intersection self (other : Set) = - other_map = other.underlying_map - new_map = self.underlying_map.keys.fold Map.empty m-> el-> - if other_map.contains_key el then m.insert el Nothing else m - Set.Value new_map + intersection : Hashset -> Hashset + intersection self (other : Hashset) = + other_dictionary = other.underlying_dictionary + dictionary = self.underlying_dictionary.keys.fold Dictionary.empty m-> el-> + if other_dictionary.contains_key el then m.insert el Nothing else m + Hashset.Value dictionary ## ICON join Computes a set difference. Returns the set that contains all elements of this set that are not in the other set. - difference : Set -> Set - difference self (other : Set) = - other_map = other.underlying_map - new_map = self.underlying_map.keys.fold Map.empty m-> el-> - if other_map.contains_key el then m else m.insert el Nothing - Set.Value new_map + difference : Hashset -> Hashset + difference self (other : Hashset) = + other_dictionary = other.underlying_dictionary + dictionary = self.underlying_dictionary.keys.fold Dictionary.empty m-> el-> + if other_dictionary.contains_key el then m else m.insert el Nothing + Hashset.Value dictionary ## PRIVATE to_text : Text - to_text self = self.to_vector.map .pretty . join ", " "Set{" "}" + to_text self = self.to_vector.map .pretty . join ", " "Hashset{" "}" ## PRIVATE -type Set_Comparator +type Hashset_Comparator ## PRIVATE compare x y = if x.size != y.size then Nothing else diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso index c9c689ca2e7..07fd19969dd 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso @@ -2,7 +2,7 @@ import project.Any.Any import project.Data.Array.Array import project.Data.Array_Proxy.Array_Proxy import project.Data.Decimal.Decimal -import project.Data.Map.Map +import project.Data.Dictionary.Dictionary import project.Data.Numbers.Float import project.Data.Numbers.Integer import project.Data.Numbers.Number @@ -252,13 +252,13 @@ type JS_Object ## GROUP Logical ICON metadata - Returns True iff the Map is empty, i.e., does not have any entries. + Returns True if the JS_Object is empty, i.e., does not have any entries. is_empty : Boolean is_empty self = self.length == 0 ## GROUP Logical ICON metadata - Returns True iff the Map is not empty, i.e., has at least one entry. + Returns True if the JS_Object is not empty, i.e., has at least one entry. not_empty : Boolean not_empty self = self.is_empty.not @@ -304,10 +304,10 @@ type JS_Object Creates an Enso object from the JS_Object. into : Any -> Any into self target_type = case target_type of - JS_Object -> self - Vector -> self.to_vector - Map -> Map.from_vector self.to_vector - _ -> + JS_Object -> self + Vector -> self.to_vector + Dictionary -> Dictionary.from_vector self.to_vector + _ -> ## First try a conversion Panic.catch No_Such_Conversion (self.to target_type) _-> ## If that fails, try to construct the type diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json/Extensions.enso index 33a5497e31c..53aa4bd0a58 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json/Extensions.enso @@ -2,10 +2,10 @@ import project.Any.Any import project.Data.Array.Array import project.Data.Array_Proxy.Array_Proxy import project.Data.Decimal.Decimal +import project.Data.Dictionary.Dictionary import project.Data.Json.JS_Object import project.Data.Json.Json import project.Data.Locale.Locale -import project.Data.Map.Map import project.Data.Numbers.Float import project.Data.Numbers.Integer import project.Data.Numbers.Number @@ -182,10 +182,10 @@ Locale.to_js_object self = For Map, this is serialized as a Vector of Key-Value pairs. Enso Maps support arbitrary types as map keys, so we cannot serialize them into JS Objects because there only strings are accepted as keys. -Map.to_js_object : JS_Object -Map.to_js_object self = - map_vector = self.to_vector - map_vector.map p-> [p.first.to_js_object, p.second.to_js_object] +Dictionary.to_js_object : JS_Object +Dictionary.to_js_object self = + as_vector = self.to_vector + as_vector.map p-> [p.first.to_js_object, p.second.to_js_object] ## PRIVATE ICON convert diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso index e9075f8901f..f6508fc67a8 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso @@ -1,436 +1,37 @@ import project.Any.Any -import project.Data.Numbers.Integer -import project.Data.Pair.Pair -import project.Data.Text.Text import project.Data.Vector.Vector import project.Error.Error -import project.Errors.Illegal_Argument.Illegal_Argument -import project.Errors.No_Such_Key.No_Such_Key -import project.Nothing.Nothing -import project.Panic.Panic +import project.Errors.Deprecated.Deprecated from project.Data.Boolean import Boolean, False, True -from project.Data.Text.Extensions import all -## A key-value store. It is possible to use any type as keys and values and mix them in - one Map. Keys are checked for equality based on their hash code and `==` operator, which - is both an internal part of Enso. Enso is capable of computing a hash code, and checking - for equality any objects that can appear in Enso - primitives, Atoms, values coming from - different languages, etc. - - For keys that are not reflexive, like `Number.nan`, - [Same Value equality specification](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#same-value-zero_equality) - is used. This means that both `Number.nan` and types with comparators that violate - reflexivity (e.g. their `compare` method always returns `Nothing`) can be used as keys - in the Map. - - A single key-value pair is called an *entry*. - - It is possible to pass a Map created in Enso to foreign functions, where it will be treated - as appropriate map structures - in Python that is a dictionary, and in JavaScript, it is - a `Map`. And likewise, it is possible to pass a foreign map into Enso, where it will be - treated as a Map. -@Builtin_Type +## PRIVATE + Deprecate place holder for the Map type. type Map key value ## PRIVATE - ADVANCED - Returns an empty map. - empty : Map - empty = @Builtin_Method "Map.empty" + DEPRECATED Use Dictionary.empty instead. + empty : Any ! Deprecated + empty = + Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "empty" "Deprecated: `Map.empty` has been replaced by `Dictionary.empty`.") ## PRIVATE - ADVANCED - Returns a single-element map with the given key and value. - A Call to `Map.singleton key value` is the same as a call to - `Map.empty.insert key value`. + DEPRECATED Use Dictionary.singleton instead. + singleton : Any -> Any -> Any ! Deprecated + singleton key value = + _ = [key, value] + Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "singleton" "Deprecated: `Map.singleton` has been replaced by `Dictionary.singleton`.") - Arguments: - - key: The key to to use for `value` in the map. - - value: The value to store under 'key' in the map. - - > Example - Create a single element map storing the key "my_key" and the value 2. - - import Standard.Base.Data.Map.Map - - example_singleton = Map.singleton "my_key" 2 - singleton : Any -> Any -> Map - singleton key value = Map.empty.insert key value - - ## ALIAS dictionary, lookup table - GROUP Constants + ## PRIVATE ICON convert - Builds a map from two Vectors. The first vector contains the keys, and - the second vector contains the values. The two vectors must be of the - same length. - - Arguments: - - keys: A vector of keys. - - values: A vector of values. - - error_on_duplicates: A flag which specifies if duplicate keys on the - input vector should result in an error. By default, set to `True`, - meaning that if two entries in the vector share the same key, an - `Illegal_Argument` error is raised. If set to `False`, the last entry - with a given key will be kept. - from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Map ! Illegal_Argument + DEPRECATED Use Dictionary.from_keys_and_values instead. + from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Any ! Deprecated from_keys_and_values keys:Vector values:Vector error_on_duplicates:Boolean=True = - if keys.length != values.length then Error.throw (Illegal_Argument.Error "`Map.from_keys_and_values` encountered two vectors of different lengths.") else - keys.fold_with_index Map.empty current-> idx-> key-> - if error_on_duplicates.not || (current.contains_key key . not) then current.insert key (values.at idx) else - Error.throw (Illegal_Argument.Error "`Map.from_keys_and_values` encountered duplicate key: "+key.to_display_text) + _ = [keys, values, error_on_duplicates] + Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "from_keys_and_values" "Deprecated: `Map.from_keys_and_values` has been replaced by `Dictionary.from_keys_and_values`.") - ## ALIAS dictionary, lookup table - GROUP Constants + ## PRIVATE ICON convert - Builds a map from a vector of key-value pairs, with each key-value pair - represented as a 2 element vector. - - Arguments: - - vec: A vector of key-value pairs (2 element vectors). - - error_on_duplicates: A flag which specifies if duplicate keys on the - input vector should result in an error. By default, set to `True`, - meaning that if two entries in the vector share the same key, an - `Illegal_Argument` error is raised. If set to `False`, the last entry - with a given key will be kept. - - > Example - Building a map containing two key-value pairs. - - import Standard.Base.Data.Map.Map - - example_from_vector = Map.from_vector [["A", 1], ["B", 2]] - from_vector : Vector Any -> Boolean -> Map ! Illegal_Argument + DEPRECATED Use Dictionary.from_vector instead. + from_vector : Vector Any -> Boolean -> Any ! Deprecated from_vector vec error_on_duplicates=True = - vec.fold Map.empty m-> el-> if el.length != 2 then Error.throw (Illegal_Argument.Error "`Map.from_vector` encountered an invalid value. Each value in the vector has to be a key-value pair - it must have exactly 2 elements.") else - key = el.at 0 - value = el.at 1 - if error_on_duplicates.not || (m.contains_key key . not) then m.insert key value else - Error.throw (Illegal_Argument.Error "`Map.from_vector` encountered duplicate key: "+key.to_display_text) - - ## GROUP Logical - ICON metadata - Returns True iff the Map is empty, i.e., does not have any entries. - is_empty : Boolean - is_empty self = self.size == 0 - - ## GROUP Logical - ICON metadata - Returns True iff the Map is not empty, i.e., has at least one entry. - not_empty : Boolean - not_empty self = self.is_empty.not - - ## GROUP Metadata - ICON metadata - Returns the number of entries in this map. - size : Integer - size self = @Builtin_Method "Map.size" - - ## GROUP Metadata - ICON metadata - Returns the number of entries in this map. - length : Integer - length self = self.size - - ## GROUP Calculations - ICON row_add - Inserts a key-value mapping into this map, overriding any existing - instance of `key` with the new `value`. - - Note that since the return type is also a `Map`, multiple `insert` - calls can be chained, e.g., `map.insert "A" 1 . insert "B" 2`. - - Due to the limitation of the current implementation, inserts with a - key that is already contained in the map, or insert on a map instance that - is re-used in other computations, have a linear time complexity. - For all the other cases, the time complexity of this method is constant. - - Arguments: - - key: The key to insert the value for. - - value: The value to associate with the `key`. - - > Example - Insert the value "seven" into the map for the key 7. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_insert = Examples.map.insert 7 "seven" - insert : Any -> Any -> Map - insert self key value = @Builtin_Method "Map.insert" - - ## GROUP Selections - ICON table_clean - Removes an entry specified by the given key from this map, and - returns a new map without this entry. Throw `No_Such_Key.Error` - if `key` is not present. - - Arguments: - - key: The key to look up in the map. - - > Example - Remove key "A" from a map - - import Standard.Data.Map.Map - - Examples.map.remove "A" - - remove : Any -> Map ! No_Such_Key - remove self key = - Panic.catch Any (self.remove_builtin key) _-> - Error.throw (No_Such_Key.Error self key) - - ## GROUP Selections - ICON parse3 - Gets the value associated with `key` in this map, or throws a - `No_Such_Key.Error` if `key` is not present. - - This method has a constant time complexity. - - Arguments: - - key: The key to look up in the map. - - > Example - Looks up the value for the key "A" in a map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_at = Examples.map.at "A" - at : Any -> Any ! No_Such_Key - at self key = self.get key (Error.throw (No_Such_Key.Error self key)) - - ## ICON parse3 - Gets the value associated with `key` in this map, or returns - `if_missing` if it isn't present. - - This method has a constant time complexity. - - Arguments: - - key: The key to look up in the map. - - if_missing: The value to use if the key isn't present. - - > Example - Get the value for the key 2 in a map or instead return "zero" if it - isn't present. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_get = Examples.map.get 2 "zero" - get : Any -> Any -> Any - get self key ~if_missing=Nothing = self.get_builtin key if_missing - - ## GROUP Logical - ICON preparation - Returns True iff the Map contains the given `key`. - contains_key : Any -> Boolean - contains_key self key = @Builtin_Method "Map.contains_key" - - ## GROUP Selections - ICON select_column - Returns an unsorted vector of all the keys in this Map. - keys : Vector Any - keys self = self.to_vector.map pair-> pair.at 0 - - ## GROUP Selections - ICON select_column - Returns an unsorted vector of all the values in this Map. - values : Vector Any - values self = self.to_vector.map pair-> pair.at 1 - - ## ICON column_add - Maps a function over each value in this map. - - Arguments: - - function: The function to apply to each value in the map, taking a - value and returning a value. - - > Example - Append "_word" to all values in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_map = Examples.map.map (+ "_word") - map : (Any -> Any) -> Map - map self function = - kv_func = _ -> function - self.map_with_key kv_func - - ## ICON column_add - Maps a function over each key-value pair in the map, transforming the - value. - - Arguments: - - function: The function to apply to each key and value in the map, - taking a key and a value and returning a value. - - > Example - Prepend the keys to the values in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_map_with_key = - Examples.map.map_with_key (k -> v -> k.to_text + "-" + v) - map_with_key : (Any -> Any -> Any) -> Map - map_with_key self function = - Map.from_vector <| self.to_vector.map pair-> - key = pair.first - value = pair.last - [key, (function key value)] - - ## ICON column_add - Maps a function over each key in this map. - - Arguments: - - function: The function to apply to each key in the map, taking a key - and returning a key. - - > Example - Doubling all keys in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_map_keys = Examples.map.map_keys *2 - map_keys : (Any -> Any) -> Map - map_keys self function = - trans_function = k -> v -> [function k, v] - self.transform trans_function - - ## ICON column_add - Transforms the map's keys and values to create a new map. - - Arguments: - - function: The function used to transform the map, taking a key and a - value and returning a pair of `[key, value]`. - - ! Error Conditions - - If multiple map entries end up with duplicate keys after the - transformation, an `Illegal_Argument.Error` is thrown. - - > Example - Turn all keys into `Text` and append "_word" to the values in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_transform = - Examples.map.transform (k -> v -> [k.to_text, v + "_word"]) - transform : (Any -> Any -> [Any, Any]) -> Map - transform self function = - func_pairs = p -> function (p.at 0) (p.at 1) - vec_transformed = self.to_vector.map func_pairs - new_map = Map.from_vector vec_transformed error_on_duplicates=True - new_map.catch Illegal_Argument error-> - case error.message.starts_with "`Map.from_vector` encountered duplicate key" of - True -> - new_message = error.message.replace "from_vector" "transform" - Error.throw (Illegal_Argument.Error new_message error.cause) - False -> new_map - - ## ICON transform4 - Combines the values in the map. - - Arguments: - - init: The initial value for the fold. - - function: A binary function to apply to pairs of values in the map. - - > Example - Find the length of the longest word in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_fold = Examples.map.fold 0 (l -> r -> l.max r.length) - fold : Any -> (Any -> Any -> Any) -> Any - fold self init function = self.values.fold init function - - ## ICON transform4 - Combines the key-value pairs in the map. - - Arguments: - - init: The initial value for the fold. - - function: A function taking the left value, the current key, and the - current value, and combining them to yield a single value. - - > Example - Glue the values in the map together with the keys. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_fold_with_key = - Examples.map.fold_with_key "" (l -> k -> v -> l + k.to_text + v) - fold_with_key : Any -> (Any -> Any -> Any -> Any) -> Any - fold_with_key self init function = - self.to_vector.fold init acc-> pair-> - function acc pair.first pair.last - - ## PRIVATE - ADVANCED - Applies a function to each value in the map. - - Arguments: - - function: The function to apply to each value in the map, taking a - value and returning anything. - - This method does not return the results, so it is only useful for performing - computations with side-effects. - - If the function returns a dataflow error, the error is converted to a - panic and thrown immediately stopping further processing. - - > Example - Printing each value in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_each = Examples.map.each IO.println - each : (Any -> Any) -> Nothing - each self function = - kv_func = _ -> function - self.each_with_key kv_func - - ## PRIVATE - ADVANCED - Applies a function to each key-value pair in the map. - - Arguments: - - function: The function to apply to each key-value pair in the map, - taking a key and a value and returning anything. - - This method does not return the results, so it is only useful for performing - computations with side-effects. - - > Example - Printing each key and value in the map. - - import Standard.Base.Data.Map.Map - import Standard.Examples - - example_each_with_key = Examples.map.each_with_key k->v-> - IO.println k - IO.println v - each_with_key : (Any -> Any -> Any) -> Nothing - each_with_key self function = - self.to_vector.each pair-> - function pair.first pair.last - - ## GROUP Conversions - ICON convert - Returns an unsorted vector of key-value pairs (nested 2 element vectors). - `Map.from_vector` method is an inverse method, so the following expression - is true for all maps: `Map.from_vector map.to_vector == map`. - to_vector : Vector Any - to_vector self = @Builtin_Method "Map.to_vector" - - ## PRIVATE - Returns a text representation of this Map. - to_text : Text - to_text self = @Builtin_Method "Map.to_text" - - ## PRIVATE - get_builtin : Any -> Any -> Any - get_builtin self key ~if_missing = @Builtin_Method "Map.get_builtin" + _ = [vec, error_on_duplicates] + Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "from_vector" "Deprecated: `Map.from_vector` has been replaced by `Dictionary.from_vector`.") diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex.enso index 6b0179c258b..e35b6762e19 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex.enso @@ -1,8 +1,8 @@ import project.Any.Any import project.Data.Array.Array +import project.Data.Dictionary.Dictionary import project.Data.Filter_Condition.Filter_Condition import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Numbers.Integer import project.Data.Range.Range import project.Data.Text.Case_Sensitivity.Case_Sensitivity @@ -379,15 +379,16 @@ type Regex Return a vector of all named group names. named_groups : Vector Text named_groups self = - map = polyglot_map_to_map self.internal_regex_object.groups - map.keys + dictionary = polyglot_map_to_dictionary self.internal_regex_object.groups + dictionary.keys ## ICON metadata - Return a map from group number to group name. Only includes named groups. - group_nums_to_names : Map Integer Text + Return a Dictionary from group number to group name. Only includes named + groups. + group_nums_to_names : Dictionary Integer Text group_nums_to_names self = - map = polyglot_map_to_map self.internal_regex_object.groups - map.transform k-> v-> [v.at 0, k] + dictionary = polyglot_map_to_dictionary self.internal_regex_object.groups + dictionary.transform k-> v-> [v.at 0, k] ## ICON text Escape the special characters in `expression` such that the result is a @@ -419,20 +420,20 @@ type Regex Regex.compile self.pattern case_insensitive ## PRIVATE - Convert the polyglot map to a Map. -polyglot_map_to_map : Any -> Map Any Any -polyglot_map_to_map map = + Convert the polyglot map to a Dictionary. +polyglot_map_to_dictionary : Any -> Dictionary Any Any +polyglot_map_to_dictionary map = polyglot_keys = Polyglot.get_members map keys = Vector.from_polyglot_array polyglot_keys pairs = keys.map key-> [key, Polyglot.get_member map key] - Map.from_vector pairs + Dictionary.from_vector pairs ## PRIVATE Get the named group from the polyglot map. read_group_map : Any -> Text -> Integer | Nothing read_group_map polyglot_map name = - map = polyglot_map_to_map polyglot_map - map.get name + dictionary = polyglot_map_to_dictionary polyglot_map + dictionary.get name ## PRIVATE match_to_group_maybe : Match | Nothing -> Text | Nothing diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Match.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Match.enso index 50a566862e0..7ced03144b6 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Match.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Match.enso @@ -1,6 +1,6 @@ import project.Any.Any +import project.Data.Dictionary.Dictionary import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Numbers.Integer import project.Data.Range.Range import project.Data.Text.Regex.No_Such_Group @@ -260,7 +260,7 @@ type Match ## GROUP Metadata ICON metadata - Gets a map containing the named capturing groups for the pattern, + Gets a Dictionary containing the named capturing groups for the pattern, replacing the value for groups that did not participate in the match with `default`. @@ -279,17 +279,18 @@ type Match a named group that does not participate to the default value. > Example - Get the map of all of the named groups in this match, replacing the - value for groups that didn't participate in the match with "UNMATCHED". + Get the Dictionary of all of the named groups in this match, replacing + the value for groups that didn't participate in the match with + "UNMATCHED". pattern = Regex.compile "(.. .. )(?.+)()??(?)??" input = "aa ab abc a bc bcd" match = pattern.match input ## match.named_groups.keys.sort == ["empty", "letters"] - named_groups : Any -> Map Text (Text | Any) + named_groups : Any -> Dictionary Text (Text | Any) named_groups self default=Nothing = pattern_named_groups = self.pattern.named_groups - Map.from_vector <| + Dictionary.from_vector <| pattern_named_groups.map name-> [name, self.text name default=default] ## ICON split diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso index c6222d977fb..cea7a99f7d8 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso @@ -1,7 +1,7 @@ import project.Any.Any +import project.Data.Dictionary.Dictionary import project.Data.Json.Extensions import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Numbers.Integer import project.Data.Text.Encoding.Encoding import project.Data.Text.Text @@ -305,9 +305,9 @@ type XML_Document ## GROUP Selections ICON array_new - Gets a map containing of the attributes of an XML document. - attributes : Map Text Text ! XML_Error - attributes self = Map.empty + Gets a Dictionary containing of the attributes of an XML document. + attributes : Dictionary Text Text ! XML_Error + attributes self = Dictionary.empty ## GROUP Selections ICON metadata @@ -508,19 +508,19 @@ type XML_Element ## GROUP Selections ICON array_new - Gets a map containing of the attributes of an XML element. + Gets a Dictionary containing of the attributes of an XML element. > Example XML_Document.from_text 'hello' . root_element . attributes - # => Map.from_vector [["bar", "one"]] - attributes : Map Text Text ! XML_Error + # => Dictionary.from_vector [["bar", "one"]] + attributes : Dictionary Text Text ! XML_Error attributes self = XML_Error.handle_java_exceptions <| named_node_map = self.java_element.getAttributes keys_and_values = 0.up_to named_node_map.getLength . map i-> node = named_node_map.item i [node.getNodeName, node.getNodeValue] - Map.from_vector keys_and_values + Dictionary.from_vector keys_and_values ## GROUP Selections ICON metadata diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Enso_Secret.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Enso_Secret.enso index e58b05e77dd..79b7e852189 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Enso_Secret.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Enso_Secret.enso @@ -1,6 +1,6 @@ import project.Data.Base_64.Base_64 +import project.Data.Dictionary.Dictionary import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Text.Text import project.Data.Vector.Vector import project.Enso_Cloud.Enso_File.Enso_Asset_Type @@ -56,7 +56,7 @@ type Enso_Secret handle_already_exists _ = message = "A secret with the name " + name.pretty + " already exists inside of directory " + parent_dir.name + "." Error.throw (Illegal_Argument.Error message) - error_handlers = Map.from_vector [["resource_already_exists", handle_already_exists]] + error_handlers = Dictionary.from_vector [["resource_already_exists", handle_already_exists]] id = Utils.http_request_as_json HTTP_Method.Post Utils.secrets_api body error_handlers=error_handlers Enso_Secret.Value name id path diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Enso_File_Helpers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Enso_File_Helpers.enso index d68ad9ffc60..3952e82a5d5 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Enso_File_Helpers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Enso_File_Helpers.enso @@ -1,9 +1,9 @@ private import project.Any.Any +import project.Data.Dictionary.Dictionary import project.Data.Json.Invalid_JSON import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Text.Text import project.Enso_Cloud.Enso_File.Enso_Asset_Type import project.Enso_Cloud.Enso_File.Enso_File @@ -44,7 +44,7 @@ upload_file (local_file : File) (destination : Enso_File) (replace_existing : Bo The `create_action` function is called with the existing asset for the parent directory and for the file, if it already exists, or `Nothing` otherwise, and with a mapping of error handlers that may be added to the request. -generic_create_asset (destination : Enso_File) (allow_existing : Boolean) (create_action : Existing_Enso_Asset -> (Existing_Enso_Asset | Nothing) -> Map -> Any) -> Any = +generic_create_asset (destination : Enso_File) (allow_existing : Boolean) (create_action : Existing_Enso_Asset -> (Existing_Enso_Asset | Nothing) -> Dictionary -> Any) -> Any = parent_directory = destination.parent if parent_directory.is_nothing then Error.throw (Illegal_Argument.Error "Please provide an asset name inside of the root directory.") else parent_directory_asset = Existing_Enso_Asset.get_asset_reference_for parent_directory @@ -55,7 +55,7 @@ generic_create_asset (destination : Enso_File) (allow_existing : Boolean) (creat File_Error.Not_Found _ -> Nothing _ -> Error.throw error if existing_asset.is_nothing.not && allow_existing.not then Error.throw (File_Error.Already_Exists destination) else - error_handlers = if existing_asset.is_nothing.not then Map.empty else + error_handlers = if existing_asset.is_nothing.not then Dictionary.empty else ## Currently we just report the race condition and request the user to re-run. We don't retry automatically because it is harder than it seems - the `create_action` usually depends on some user code that is writing to a stream (the callback given to `with_output_stream`). @@ -64,7 +64,7 @@ generic_create_asset (destination : Enso_File) (allow_existing : Boolean) (creat into memory or a temporary file and relies on that for the retry. For now, reporting the race condition in a sane way seemed like the simplest choice. This situation should be very rare. - Map.from_vector [["resource_already_exists", Error.throw (Illegal_State.Error "A race-condition has been encountered - another process has created a colliding resource at "+destination.path+". Please try re-running the operation.")]] + Dictionary.from_vector [["resource_already_exists", Error.throw (Illegal_State.Error "A race-condition has been encountered - another process has created a colliding resource at "+destination.path+". Please try re-running the operation.")]] create_action parent_directory_asset existing_asset error_handlers ## PRIVATE diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Existing_Enso_Asset.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Existing_Enso_Asset.enso index 7e7971eaed5..8c786aa0434 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Existing_Enso_Asset.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Existing_Enso_Asset.enso @@ -1,7 +1,7 @@ private +import project.Data.Dictionary.Dictionary import project.Data.Json.JS_Object -import project.Data.Map.Map import project.Data.Text.Text import project.Data.Time.Date_Time.Date_Time import project.Data.Time.Date_Time_Formatter.Date_Time_Formatter @@ -83,7 +83,7 @@ type Existing_Enso_Asset Resolves a path to an existing asset in the cloud. resolve_path (path : Text) ~if_not_found = path.if_not_error <| handle_not_found _ = Error.throw Not_Found - error_handlers = Map.from_vector [["resource_missing", handle_not_found]] + error_handlers = Dictionary.from_vector [["resource_missing", handle_not_found]] uri = ((URI.from Utils.cloud_root_uri) / "path/resolve") . add_query_argument "path" path response = Utils.http_request_as_json HTTP_Method.Get uri error_handlers=error_handlers diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso index 32636acaaa6..67684659010 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso @@ -1,8 +1,8 @@ private import project.Any.Any +import project.Data.Dictionary.Dictionary import project.Data.Json.Invalid_JSON -import project.Data.Map.Map import project.Data.Numbers.Integer import project.Data.Text.Text import project.Data.Time.Duration.Duration @@ -72,7 +72,7 @@ flush_caches = CloudAPI.flushCloudCaches ## PRIVATE Performs a standard request to the Enso Cloud API, parsing the result as JSON. -http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Map Text (Any -> Any) = Map.empty) (retries : Integer = 3) -> Any ! Enso_Cloud_Error = +http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Any ! Enso_Cloud_Error = response = http_request method url body additional_headers error_handlers retries response.decode_as_json.catch Invalid_JSON error-> Error.throw (Enso_Cloud_Error.Invalid_Response_Payload error) @@ -87,7 +87,7 @@ http_request_as_json (method : HTTP_Method) (url : URI) (body : Request_Body = R Custom error handlers can be provided as a mapping from error codes (defined in the cloud project) to functions that take the full JSON payload and return a custom error. -http_request (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Map Text (Any -> Any) = Map.empty) (retries : Integer = 3) -> Response ! Enso_Cloud_Error = method.if_not_error <| url.if_not_error <| body.if_not_error <| additional_headers.if_not_error <| +http_request (method : HTTP_Method) (url : URI) (body : Request_Body = Request_Body.Empty) (additional_headers : Vector = []) (error_handlers : Dictionary Text (Any -> Any) = Dictionary.empty) (retries : Integer = 3) -> Response ! Enso_Cloud_Error = method.if_not_error <| url.if_not_error <| body.if_not_error <| additional_headers.if_not_error <| all_headers = [authorization_header] + additional_headers as_connection_error err = Error.throw (Enso_Cloud_Error.Connection_Error err) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Array_Like_Helpers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Array_Like_Helpers.enso index 1915c7428cf..e08a08fef8b 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Array_Like_Helpers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Array_Like_Helpers.enso @@ -3,9 +3,9 @@ private import project.Any.Any import project.Data.Array.Array import project.Data.Array_Proxy.Array_Proxy +import project.Data.Dictionary.Dictionary import project.Data.Index_Sub_Range.Index_Sub_Range import project.Data.List.List -import project.Data.Map.Map import project.Data.Maybe.Maybe import project.Data.Numbers.Integer import project.Data.Pair.Pair @@ -166,7 +166,7 @@ private on_problems_to_number on_problems:Problem_Behavior = case on_problems of distinct vector on = Vector.build builder-> - vector.fold Map.empty existing-> + vector.fold Dictionary.empty existing-> item-> key = on item if (existing.get key False) then existing else @@ -174,7 +174,7 @@ distinct vector on = existing.insert key True duplicates vector on = Vector.build builder-> - counts = vector.fold Map.empty current-> item-> + counts = vector.fold Dictionary.empty current-> item-> key = on item count = current.get key 0 current.insert key count+1 diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso index afde3f395f5..fa1434f556e 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso @@ -2,8 +2,10 @@ export project.Any.Any export project.Data export project.Data.Array.Array export project.Data.Decimal.Decimal +export project.Data.Dictionary.Dictionary export project.Data.Filter_Condition.Filter_Action export project.Data.Filter_Condition.Filter_Condition +export project.Data.Hashset.Hashset export project.Data.Index_Sub_Range.Index_Sub_Range export project.Data.Interval.Bound export project.Data.Interval.Interval @@ -25,7 +27,6 @@ export project.Data.Pair.Pair export project.Data.Range.Range export project.Data.Raw_Response export project.Data.Regression -export project.Data.Set.Set export project.Data.Sort_Direction.Sort_Direction export project.Data.Statistics.Rank_Method export project.Data.Statistics.Statistic diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso index ead500bc394..62b19da7795 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso @@ -1,7 +1,7 @@ import project.Any.Any -import project.Data.Map.Map +import project.Data.Dictionary.Dictionary +import project.Data.Hashset.Hashset import project.Data.Pair.Pair -import project.Data.Set.Set import project.Data.Text.Encoding.Encoding import project.Data.Text.Text import project.Data.Time.Duration.Duration @@ -261,8 +261,8 @@ resolve_body_to_publisher_and_boundary body:Request_Body = Build a BodyPublisher from the given form data. The pair's second value is a content boundary in the case of a `multipart/form-data` form; otherwise, Nothing -build_form_body_publisher : Map Text (Text | File) -> Boolean -> Pair BodyPublisher Text -build_form_body_publisher (form_data:(Map Text (Text | File))) (url_encoded:Boolean=False) = case url_encoded of +build_form_body_publisher : Dictionary Text (Text | File) -> Boolean -> Pair BodyPublisher Text +build_form_body_publisher (form_data:(Dictionary Text (Text | File))) (url_encoded:Boolean=False) = case url_encoded of True -> body_builder = UrlencodedBodyBuilder.new form_data.map_with_key key-> value-> @@ -280,15 +280,15 @@ build_form_body_publisher (form_data:(Map Text (Text | File))) (url_encoded:Bool Pair.new body_builder.build boundary ## PRIVATE -fetch_methods : Set HTTP_Method -fetch_methods = Set.from_vector [HTTP_Method.Get, HTTP_Method.Head, HTTP_Method.Options] +fetch_methods : Hashset HTTP_Method +fetch_methods = Hashset.from_vector [HTTP_Method.Get, HTTP_Method.Head, HTTP_Method.Options] ## PRIVATE -post_methods : Set HTTP_Method -post_methods = Set.from_vector [HTTP_Method.Post, HTTP_Method.Put, HTTP_Method.Patch, HTTP_Method.Delete] +post_methods : Hashset HTTP_Method +post_methods = Hashset.from_vector [HTTP_Method.Post, HTTP_Method.Put, HTTP_Method.Patch, HTTP_Method.Delete] ## PRIVATE -check_method : Set HTTP_Method -> Any -> Any -> Any ! Illegal_Argument +check_method : Hashset HTTP_Method -> Any -> Any -> Any ! Illegal_Argument check_method allowed_methods method ~action = if allowed_methods.contains method then action else Error.throw (Illegal_Argument.Error ("Unsupported method " + method.to_display_text)) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request.enso index d873de1bb18..c282eef39b7 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request.enso @@ -1,5 +1,5 @@ import project.Any.Any -import project.Data.Map.Map +import project.Data.Dictionary.Dictionary import project.Data.Pair.Pair import project.Data.Text.Text import project.Data.Vector.Vector @@ -249,10 +249,10 @@ type Request example_delete = Request.delete (URI.parse "http://example.com") . with_form [] - with_form : (Vector | Map) -> Request + with_form : (Vector | Dictionary) -> Request with_form self parts = form_data = case parts of - _ : Vector -> Map.from_vector parts - _ : Map -> parts + _ : Vector -> Dictionary.from_vector parts + _ : Dictionary -> parts new_body = Request_Body.Form_Data form_data Request.Value self.method self.uri self.headers new_body . with_headers [Header.application_x_www_form_urlencoded] diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request_Body.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request_Body.enso index cdbdeb45cfb..84a42d25d9a 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request_Body.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Request_Body.enso @@ -1,5 +1,5 @@ import project.Any.Any -import project.Data.Map.Map +import project.Data.Dictionary.Dictionary import project.Data.Text.Encoding.Encoding import project.Data.Text.Text import project.Network.HTTP.Header.Header @@ -36,7 +36,7 @@ type Request_Body - form_data: the form fields (text or file) to be sent - url_encoded: if true, use a URL-encoded form; otherwise, use a multi-part encoding. - Form_Data (form_data:(Map Text (Text | File))) (url_encoded:Boolean=False) + Form_Data (form_data:(Dictionary Text (Text | File))) (url_encoded:Boolean=False) ## Empty request body; used for GET Empty diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso index 696d54bb9f3..77760bb6b66 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP/Response.enso @@ -75,7 +75,7 @@ type Response import Standard.Examples - example_headers = Map.from_vector error_on_duplicates=True (Examples.get_response.headers.map h-> [h.name, h.value]) + example_headers = Dictionary.from_vector error_on_duplicates=True (Examples.get_response.headers.map h-> [h.name, h.value]) headers : Vector Header headers self = # This is a mapping that maps a header name to a list of values (since headers may be duplicated). diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso index b17182ff52c..857c9b3f765 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso @@ -1,8 +1,6 @@ import project.Any.Any import project.Data.Array.Array -import project.Data.Map.Map import project.Data.Range.Range -import project.Data.Set.Set import project.Data.Text.Text import project.Data.Time.Date.Date import project.Data.Time.Date_Range.Date_Range diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Warning.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Warning.enso index f933851ddc7..b4bae445f41 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Warning.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Warning.enso @@ -1,9 +1,9 @@ import project.Any.Any import project.Data.Array.Array +import project.Data.Hashset.Hashset import project.Data.Maybe.Maybe import project.Data.Numbers.Integer import project.Data.Pair.Pair -import project.Data.Set.Set import project.Data.Vector.Map_Error import project.Data.Vector.No_Wrap import project.Data.Vector.Vector diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso index c30cbf55154..7343d5a1cdc 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso @@ -168,11 +168,11 @@ type Connection Nothing -> Nothing _ : Vector -> types _ -> [types] - name_map = Map.from_vector [["TABLE_CAT", "Database"], ["TABLE_SCHEM", "Schema"], ["TABLE_NAME", "Name"], ["TABLE_TYPE", "Type"], ["REMARKS", "Description"], ["TYPE_CAT", "Type Database"], ["TYPE_SCHEM", "Type Schema"], ["TYPE_NAME", "Type Name"]] + name_dict = Dictionary.from_vector [["TABLE_CAT", "Database"], ["TABLE_SCHEM", "Schema"], ["TABLE_NAME", "Name"], ["TABLE_TYPE", "Type"], ["REMARKS", "Description"], ["TYPE_CAT", "Type Database"], ["TYPE_SCHEM", "Type Schema"], ["TYPE_NAME", "Type Name"]] result = self.jdbc_connection.with_metadata metadata-> table = Managed_Resource.bracket (metadata.getTables database schema name_like types_vector) .close result_set-> result_set_to_table result_set self.dialect.get_type_mapping.make_column_fetcher - renamed = table.rename_columns name_map + renamed = table.rename_columns name_dict if all_fields then renamed else renamed.select_columns ["Database", "Schema", "Name", "Type", "Description"] case include_hidden of diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso index f9c309a0945..9a03f1715f6 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso @@ -544,17 +544,17 @@ type DB_Table > Example Rename the "Alpha" column to "Beta" - table.rename_columns (Map.from_vector [["Alpha", "Beta"]]) + table.rename_columns (Dictionary.from_vector [["Alpha", "Beta"]]) > Example Rename the last column to "LastColumn" - table.rename_columns (Map.from_vector [[-1, "LastColumn"]]) + table.rename_columns (Dictionary.from_vector [[-1, "LastColumn"]]) > Example Rename the "Alpha" column to "Beta" and last column to "LastColumn" - table.rename_columns (Map.from_vector [["Alpha", "Beta"], [-1, "LastColumn"]]) + table.rename_columns (Dictionary.from_vector [["Alpha", "Beta"], [-1, "LastColumn"]]) > Example Rename the first column to "FirstColumn" @@ -569,12 +569,12 @@ type DB_Table > Example For all columns starting with the prefix `name=`, replace it with `key:`. - table.rename_columns (Map.from_vector [["name=(.*)".to_regex, "key:$1"]]) + table.rename_columns (Dictionary.from_vector [["name=(.*)".to_regex, "key:$1"]]) @column_map Widget_Helpers.make_rename_name_vector_selector - rename_columns : Map (Text | Integer | Regex) Text | Vector Text | Vector Vector -> Case_Sensitivity -> Boolean -> Problem_Behavior -> DB_Table ! Missing_Input_Columns | Ambiguous_Column_Rename | Too_Many_Column_Names_Provided | Invalid_Column_Names | Duplicate_Output_Column_Names - rename_columns self (column_map:(Table | Map | Vector)=["Column"]) (case_sensitivity:Case_Sensitivity=..Default) (error_on_missing_columns:Boolean=True) (on_problems:Problem_Behavior=..Report_Warning) = case column_map of + rename_columns : Table | Dictionary (Text | Integer | Regex) Text | Vector Text | Vector Vector -> Case_Sensitivity -> Boolean -> Problem_Behavior -> DB_Table ! Missing_Input_Columns | Ambiguous_Column_Rename | Too_Many_Column_Names_Provided | Invalid_Column_Names | Duplicate_Output_Column_Names + rename_columns self (column_map:(Table | Dictionary | Vector)=["Column"]) (case_sensitivity:Case_Sensitivity=..Default) (error_on_missing_columns:Boolean=True) (on_problems:Problem_Behavior=..Report_Warning) = case column_map of _ : Table -> - resolved = Table_Helpers.read_name_map_from_table column_map + resolved = Table_Helpers.read_name_mapping_from_table column_map self.rename_columns resolved case_sensitivity error_on_missing_columns on_problems _ -> new_names = Table_Helpers.rename_columns self.column_naming_helper self.internal_columns column_map case_sensitivity error_on_missing_columns on_problems @@ -1035,26 +1035,26 @@ type DB_Table Warning.set result [] ## PRIVATE - A helper that creates a two-column table from a Map. + A helper that creates a two-column table from a Dictionary. - The keys of the `Map` become the first column, with name - `key_column_name`, and the values of the `Map` become the second column, - with name `value_column_name`. + The keys of the `Dictionary` become the first column, with name + `key_column_name`, and the values become the second column, with name + `value_column_name`. - For the in-memory database, the `Map` can be empty. For the database - backends, it must not be empty. + For the in-memory database, the `Dictionary` can be empty. For the + database backends, it must not be empty. Arguments: - - map: The `Map` to create the table from. + - dict: The `Dictionary` to create the table from. - key_column_name: The name to use for the first column. - value_column_name: The name to use for the second column. - make_table_from_map : Map Any Any -> Text -> Text -> Table - make_table_from_map self map key_column_name value_column_name = - total_size = map.size * 2 + make_table_from_dictionary : Dictionary Any Any -> Text -> Text -> Table + make_table_from_dictionary self dict key_column_name value_column_name = + total_size = dict.size * 2 - if map.is_empty then Error.throw (Illegal_Argument.Error "Map argument cannot be empty") else - if total_size > MAX_LITERAL_ELEMENT_COUNT then Error.throw (Illegal_Argument.Error "Map argument is too large ("+map.size.to_text+" entries): materialize a table into the database instead") else - keys_and_values = map.to_vector + if dict.is_empty then Error.throw (Illegal_Argument.Error "Dictionary cannot be empty") else + if total_size > MAX_LITERAL_ELEMENT_COUNT then Error.throw (Illegal_Argument.Error "Dictionary is too large ("+dict.size.to_text+" entries): materialize a table into the database instead") else + keys_and_values = dict.to_vector self.make_table_from_vectors [keys_and_values.map .first, keys_and_values.map .second] [key_column_name, value_column_name] ## PRIVATE @@ -1683,8 +1683,8 @@ type DB_Table @columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True) @from_column Widget.Text_Input @to_column Widget.Text_Input - replace : (DB_Table | Map) -> Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> DB_Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup - replace self lookup_table:(DB_Table | Map) columns:(Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type) from_column:(Text | Integer | Nothing)=Nothing to_column:(Text | Integer | Nothing)=Nothing allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning = + replace : (DB_Table | Dictionary) -> Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> DB_Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup + replace self lookup_table:(DB_Table | Dictionary) columns:(Vector (Integer | Text | Regex | By_Type) | Text | Integer | Regex | By_Type) from_column:(Text | Integer | Nothing)=Nothing to_column:(Text | Integer | Nothing)=Nothing allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning = Replace_Helpers.replace self lookup_table columns from_column to_column allow_unmatched_rows on_problems ## ALIAS join by row position diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso index 88814a6fdf7..427b22ce867 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso @@ -17,33 +17,32 @@ from project.Internal.IR.Operation_Metadata import Row_Number_Metadata type Dialect_Operations ## PRIVATE - - Operations supported by a particular SQL dialect and how they are implemeneted. + Operations supported by a particular SQL dialect and how they are + implemented. Arguments: - - operation_map: The mapping which maps operation names to their + - operations_dict: Dictionary mapping operation names to their implementations; each implementation is a function which takes SQL builders for the arguments, and optionally an additional metadata argument, and should return a SQL builder yielding code for the whole operation. - Value (operation_map:(Map Text (Vector (SQL_Builder->SQL_Builder)))) + Value (operations_dict:(Dictionary Text (Vector (SQL_Builder->SQL_Builder)))) ## PRIVATE - Creates a copy of the dialect that supports additional operations or overrides existing ones. # extend_with : Vector [Text, Vector SQL_Builder -> SQL_Builder] -> Dialect_Operations extend_with : Vector Any -> Dialect_Operations extend_with self mappings = - new_map = mappings.fold self.operation_map (m -> el -> m.insert (el.at 0) (el.at 1)) - Dialect_Operations.Value new_map + new_dict = mappings.fold self.operations_dict (m -> el -> m.insert (el.at 0) (el.at 1)) + Dialect_Operations.Value new_dict ## PRIVATE Checks if an operation is supported by the dialect. is_supported : Text -> Boolean is_supported self operation = - self.operation_map.contains_key operation + self.operations_dict.contains_key operation ## PRIVATE @@ -200,8 +199,8 @@ base_dialect_operations = contains = [["IS_IN", make_is_in], ["IS_IN_COLUMN", make_is_in_column]] types = [simple_cast] windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group]] - base_map = Map.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows) - Dialect_Operations.Value base_map + base_dict = Dictionary.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows) + Dialect_Operations.Value base_dict ## PRIVATE is_empty = lift_unary_op "IS_EMPTY" arg-> @@ -311,7 +310,7 @@ generate_expression dialect expr = case expr of escaped = value.replace "'" "''" SQL_Builder.code ("'" + escaped + "'") SQL_Expression.Operation kind arguments metadata -> - op = dialect.dialect_operations.operation_map.get kind (Error.throw <| Unsupported_Database_Operation.Error kind) + op = dialect.dialect_operations.operations_dict.get kind (Error.throw <| Unsupported_Database_Operation.Error kind) parsed_args = arguments.map (generate_expression dialect) result = op parsed_args # If the function expects more arguments, we pass the metadata as the last argument. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Database_Join_Helper.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Database_Join_Helper.enso index 4b5b19d30f1..78ca8456285 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Database_Join_Helper.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Common/Database_Join_Helper.enso @@ -70,11 +70,10 @@ type Join_Subquery_Setup ## PRIVATE Creates a mapping from names of columns in the original table to corresponding columns in the created subquery. - column_mapping : Map Text Internal_Column + column_mapping : Dictionary Text Internal_Column column_mapping self = - Map.from_vector <| - self.old_columns.zip self.new_columns old-> new-> - [old.name, new] + Dictionary.from_vector <| + self.old_columns.zip self.new_columns old->new->[old.name, new] ## PRIVATE prepare_subqueries : Connection -> DB_Table -> DB_Table -> Boolean -> Boolean -> Pair Join_Subquery_Setup diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso index 454302fc8a6..f89a2780f44 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso @@ -116,7 +116,7 @@ type Postgres_Dialect inner_table_alias = table_name_deduplicator.make_unique table.name+"_inner" setup = table.context.as_subquery inner_table_alias [table.internal_columns] new_columns = setup.new_columns.first - column_mapping = Map.from_vector <| new_columns.map c-> [c.name, c] + column_mapping = Dictionary.from_vector <| new_columns.map c-> [c.name, c] new_key_columns = key_columns.map c-> column_mapping.at c.name type_mapping = self.get_type_mapping distinct_expressions = new_key_columns.map column-> @@ -563,14 +563,14 @@ decimal_mod = Base_Generator.lift_binary_op "DECIMAL_MOD" x-> y-> x ++ " - FLOOR(CAST(" ++ x ++ " AS decimal) / CAST(" ++ y ++ " AS decimal)) * " ++ y ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e0 = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive False] e1 = [Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive False, Replace_Params.Value Text Case_Sensitivity.Insensitive True] e2 = [Replace_Params.Value Regex Case_Sensitivity.Default False, Replace_Params.Value Regex Case_Sensitivity.Default True, Replace_Params.Value Regex Case_Sensitivity.Sensitive False] e3 = [Replace_Params.Value Regex Case_Sensitivity.Sensitive True, Replace_Params.Value Regex Case_Sensitivity.Insensitive False, Replace_Params.Value Regex Case_Sensitivity.Insensitive True] e4 = [Replace_Params.Value DB_Column Case_Sensitivity.Default False, Replace_Params.Value DB_Column Case_Sensitivity.Sensitive False] - Set.from_vector <| e0 + e1 + e2 + e3 + e4 + Hashset.from_vector <| e0 + e1 + e2 + e3 + e4 ## PRIVATE replace : Vector SQL_Builder -> Any -> SQL_Builder diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Type_Mapping.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Type_Mapping.enso index 88deded846d..138133cd5a0 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Type_Mapping.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Type_Mapping.enso @@ -126,14 +126,14 @@ type Postgres_Type_Mapping Column_Fetcher_Module.default_fetcher_for_value_type value_type ## PRIVATE -simple_types_map = Map.from_vector <| +simple_types_map = Dictionary.from_vector <| ints = [[Types.SMALLINT, Value_Type.Integer Bits.Bits_16], [Types.BIGINT, Value_Type.Integer Bits.Bits_64], [Types.INTEGER, Value_Type.Integer Bits.Bits_32]] floats = [[Types.DOUBLE, Value_Type.Float Bits.Bits_64], [Types.REAL, Value_Type.Float Bits.Bits_32]] other = [[Types.DATE, Value_Type.Date], [Types.TIME, Value_Type.Time]] ints + floats + other ## PRIVATE -complex_types_map = Map.from_vector <| +complex_types_map = Dictionary.from_vector <| make_decimal sql_type = Value_Type.Decimal sql_type.precision sql_type.scale make_varchar sql_type = diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso index 198e408a891..0facd5fea18 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso @@ -125,7 +125,7 @@ type SQLite_Dialect inner_table_alias = table_name_deduplicator.make_unique table.name+"_inner" setup = table.context.as_subquery inner_table_alias [table.internal_columns] new_columns = setup.new_columns.first - column_mapping = Map.from_vector <| new_columns.map c-> [c.name, c] + column_mapping = Dictionary.from_vector <| new_columns.map c-> [c.name, c] new_key_columns = key_columns.map c-> column_mapping.at c.name type_mapping = self.get_type_mapping distinct_expressions = new_key_columns.map column-> @@ -447,10 +447,10 @@ mod_op = Base_Generator.lift_binary_op "MOD" x-> y-> x ++ " - FLOOR(CAST(" ++ x ++ " AS REAL) / CAST(" ++ y ++ " AS REAL)) * " ++ y ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Sensitive False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive True] - Set.from_vector e + Hashset.from_vector e ## PRIVATE replace : Vector SQL_Builder -> Any -> SQL_Builder diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso index 4c0eb55ad84..935383fc7d4 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso @@ -96,7 +96,7 @@ type SQLite_Type_Mapping infer_return_type : (SQL_Expression -> SQL_Type_Reference) -> Text -> Vector -> SQL_Expression -> SQL_Type_Reference infer_return_type infer_from_database_callback op_name arguments expression = _ = [infer_from_database_callback, expression] - handler = operations_map.get op_name (_ -> Error.throw (Illegal_State.Error "Impossible: Unknown operation "+op_name+". This is a bug in the Database library.")) + handler = operations_dict.get op_name (_ -> Error.throw (Illegal_State.Error "Impossible: Unknown operation "+op_name+". This is a bug in the Database library.")) sql_type = handler arguments SQL_Type_Reference.from_constant sql_type @@ -127,7 +127,7 @@ type SQLite_Type_Mapping For types like dates - we map them to unsupported type, because date operations in SQLite are currently not supported due to their weird storage. -simple_types_map = Map.from_vector <| +simple_types_map = Dictionary.from_vector <| ints = [Types.TINYINT, Types.SMALLINT, Types.BIGINT, Types.INTEGER] . map x-> [x, default_integer] floats = [Types.DOUBLE, Types.REAL, Types.FLOAT] . map x-> [x, default_float] # We treat numeric as a float, since that is what really sits in SQLite under the hood. @@ -142,13 +142,13 @@ simple_types_map = Map.from_vector <| https://www.sqlite.org/datatype3.html#affinity_name_examples However, with this the date-time columns will be mapped to the numeric type. Instead, we want to treat such columns as Text, so we override the mapping. -name_based_workarounds = Map.from_vector <| +name_based_workarounds = Dictionary.from_vector <| ["TIME", "DATE", "DATETIME", "TIMESTAMP"] . map x-> [x, default_text] ## PRIVATE Maps operation names to functions that infer its result type. -operations_map : Map Text (Vector -> SQL_Type) -operations_map = +operations_dict : Dictionary Text (Vector -> SQL_Type) +operations_dict = find_type arg = case arg of column : DB_Column -> column.value_type internal_column : Internal_Column -> @@ -198,7 +198,7 @@ operations_map = arithmetic_ops = ["ADD_NUMBER", "-", "*", "^", "%", "SUM"] merge_input_types_ops = ["ROW_MAX", "ROW_MIN", "MAX", "MIN", "FILL_NULL", "COALESCE"] others = [["IIF", handle_iif], ["CAST", handle_cast], ["CASE", handle_case], ["RUNTIME_ERROR", handle_runtime_error]] - Map.from_vector <| + Dictionary.from_vector <| v1 = always_boolean_ops.map [_, const SQLite_Types.boolean] v2 = always_floating_ops.map [_, const SQLite_Types.real] v3 = always_integer_ops.map [_, const SQLite_Types.integer] diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload_Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload_Table.enso index cec7fd97b0f..2887d9318b6 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload_Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload_Table.enso @@ -190,8 +190,8 @@ resolve_primary_key structure primary_key = case primary_key of if key.is_a Text then key else Error.throw (Illegal_Argument.Error ("Primary key must be a vector of column names, instead got a " + (Meta.type_of key . to_display_text))) validated.if_not_error <| - column_names = Set.from_vector (structure.map .name) - missing_columns = (Set.from_vector primary_key).difference column_names + column_names = Hashset.from_vector (structure.map .name) + missing_columns = (Hashset.from_vector primary_key).difference column_names if missing_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_columns.to_vector) else primary_key @@ -470,13 +470,13 @@ check_update_arguments_structure_match source_table target_table key_columns upd if source_type.can_be_widened_to target_type then [Inexact_Type_Coercion.Warning source_type target_type unavailable=False] else Error.throw (Column_Type_Mismatch.Error source_column.name target_type source_type) - source_columns = Set.from_vector source_table.column_names - target_columns = Set.from_vector target_table.column_names + source_columns = Hashset.from_vector source_table.column_names + target_columns = Hashset.from_vector target_table.column_names extra_columns = source_columns.difference target_columns if extra_columns.not_empty then Error.throw (Unmatched_Columns.Error extra_columns.to_vector) else missing_columns = target_columns.difference source_columns if missing_columns.not_empty && error_on_missing_columns then Error.throw (Missing_Input_Columns.Error missing_columns.to_vector "the source table") else - key_set = Set.from_vector key_columns + key_set = Hashset.from_vector key_columns missing_source_key_columns = key_set.difference source_columns missing_target_key_columns = key_set.difference target_columns if missing_source_key_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_source_key_columns.to_vector "the source table") else @@ -600,10 +600,10 @@ type Delete_Rows_Source check_delete_rows_arguments target_table key_values_to_delete key_columns ~continuation = check_target_table_for_update target_table <| if key_columns.is_empty then Error.throw (Illegal_Argument.Error "One or more key columns must be provided to correlate the rows to be deleted.") else - key_set = Set.from_vector key_columns - missing_target_key_columns = key_set . difference (Set.from_vector target_table.column_names) + key_set = Hashset.from_vector key_columns + missing_target_key_columns = key_set . difference (Hashset.from_vector target_table.column_names) if missing_target_key_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_target_key_columns.to_vector "the target table") else - missing_source_key_columns = key_set . difference (Set.from_vector key_values_to_delete.column_names) + missing_source_key_columns = key_set . difference (Hashset.from_vector key_values_to_delete.column_names) if missing_source_key_columns.not_empty then Error.throw (Missing_Input_Columns.Error missing_source_key_columns.to_vector "the key values to delete table") else continuation diff --git a/distribution/lib/Standard/Examples/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Examples/0.0.0-dev/src/Main.enso index 3878bdc74d3..d72fe11d854 100644 --- a/distribution/lib/Standard/Examples/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Examples/0.0.0-dev/src/Main.enso @@ -112,9 +112,9 @@ json_object = json.first list : List list = List.Cons 1 (List.Cons 2 (List.Cons 3 List.Nil)) -## A simple map that contains some numbers mapped to their word equivalents. -map : Map -map = Map.empty . insert 1 "one" . insert 3 "three" . insert 5 "five" +## A simple dictionary that contains some numbers mapped to their word equivalents. +dictionary : Dictionary +dictionary = Dictionary.empty . insert 1 "one" . insert 3 "three" . insert 5 "five" ## A dummy type that is used for example purposes. type No_Methods diff --git a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso index 089a8572c3b..6b350302457 100644 --- a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso +++ b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso @@ -119,7 +119,7 @@ type Snowflake_Dialect inner_table_alias = table_name_deduplicator.make_unique table.name+"_inner" setup = (Internals_Access.get_context table).as_subquery inner_table_alias [Internals_Access.internal_columns table] new_columns = setup.new_columns.first - column_mapping = Map.from_vector <| new_columns.map c-> [c.name, c] + column_mapping = Dictionary.from_vector <| new_columns.map c-> [c.name, c] new_key_columns = key_columns.map c-> column_mapping.at c.name type_mapping = self.get_type_mapping distinct_expressions = new_key_columns.map column-> @@ -464,14 +464,14 @@ decimal_mod = Base_Generator.lift_binary_op "DECIMAL_MOD" x-> y-> x ++ " - FLOOR(CAST(" ++ x ++ " AS decimal) / CAST(" ++ y ++ " AS decimal)) * " ++ y ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e0 = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive False] e1 = [Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive False, Replace_Params.Value Text Case_Sensitivity.Insensitive True] e2 = [Replace_Params.Value Regex Case_Sensitivity.Default False, Replace_Params.Value Regex Case_Sensitivity.Default True, Replace_Params.Value Regex Case_Sensitivity.Sensitive False] e3 = [Replace_Params.Value Regex Case_Sensitivity.Sensitive True, Replace_Params.Value Regex Case_Sensitivity.Insensitive False, Replace_Params.Value Regex Case_Sensitivity.Insensitive True] e4 = [Replace_Params.Value DB_Column Case_Sensitivity.Default False, Replace_Params.Value DB_Column Case_Sensitivity.Sensitive False] - Set.from_vector <| e0 + e1 + e2 + e3 + e4 + Hashset.from_vector <| e0 + e1 + e2 + e3 + e4 ## PRIVATE replace : Vector SQL_Builder -> Any -> SQL_Builder diff --git a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso index 2cae993f487..e472e489adf 100644 --- a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso +++ b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso @@ -118,14 +118,14 @@ type Snowflake_Type_Mapping _ -> Column_Fetcher_Module.default_fetcher_for_value_type value_type ## PRIVATE -simple_types_map = Map.from_vector <| +simple_types_map = Dictionary.from_vector <| ints = [[Types.TINYINT, Value_Type.Byte], [Types.SMALLINT, Value_Type.Integer Bits.Bits_16], [Types.BIGINT, Value_Type.Integer Bits.Bits_64], [Types.INTEGER, Value_Type.Integer Bits.Bits_32]] floats = [[Types.DOUBLE, Value_Type.Float Bits.Bits_64], [Types.REAL, Value_Type.Float Bits.Bits_32]] other = [[Types.DATE, Value_Type.Date], [Types.TIME, Value_Type.Time], [Types.BOOLEAN, Value_Type.Boolean]] ints + floats + other ## PRIVATE -complex_types_map = Map.from_vector <| +complex_types_map = Dictionary.from_vector <| make_decimal sql_type = Value_Type.Decimal sql_type.precision sql_type.scale make_varchar sql_type = diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso index 8e88dd1f706..0c944905eed 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso @@ -1716,7 +1716,7 @@ type Column True -> run_vectorized_binary_op self op_name as_vector expected_result_type=Value_Type.Boolean skip_nulls=False new_name=result_name False -> - set = Set.from_vector as_vector error_on_duplicates=False + set = Hashset.from_vector as_vector error_on_duplicates=False apply_unary_map self result_name set.contains_relational Value_Type.Boolean nothing_unchanged=False ## GROUP Standard.Base.Conversions diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Columns.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Columns.enso index 75cc10f2bc8..bbe233f7aae 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Columns.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Columns.enso @@ -20,12 +20,12 @@ Convertible_To_Columns.from (that:JS_Object) = Convertible_To_Columns.Value that.field_names (that.get _) ## PRIVATE -Convertible_To_Columns.from (that:Map) = +Convertible_To_Columns.from (that:Dictionary) = pairs = that.keys.map k-> [k.to_text, k] - field_map = pairs.if_not_error <| - Map.from_vector pairs error_on_duplicates=True . catch Illegal_Argument _-> + field_dict = pairs.if_not_error <| + Dictionary.from_vector pairs error_on_duplicates=True . catch Illegal_Argument _-> Error.throw (Illegal_Argument.Error "Cannot convert "+that.to_display_text+" to a set of columns, because its keys are duplicated when converted to text.") - Convertible_To_Columns.Value field_map.keys (k-> that.get (field_map.get k)) + Convertible_To_Columns.Value field_dict.keys (k-> that.get (field_dict.get k)) ## PRIVATE Convertible_To_Columns.from (that:Pair) = @@ -67,5 +67,5 @@ Convertible_To_Columns.from (that:XML_Element) = has_child_nodes = that_children.any (_.is_a XML_Element) children = if that_children.is_empty.not && has_child_nodes then [["Children", that_children]] else [] value = if that_children.is_empty.not && has_child_nodes.not then [["Value", that.text]] else [] - as_map = Map.from_vector (name + tags + children + value) - Convertible_To_Columns.from as_map + as_dict = Dictionary.from_vector (name + tags + children + value) + Convertible_To_Columns.from as_dict diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Rows.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Rows.enso index 8ac24810084..eae50d1d01a 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Rows.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Conversions/Convertible_To_Rows.enso @@ -54,7 +54,7 @@ Convertible_To_Rows.from that:Pair = Convertible_To_Rows.Value that.length (that Convertible_To_Rows.from that:Date_Range = Convertible_To_Rows.Value that.length (that.get _) ## PRIVATE -Convertible_To_Rows.from that:Map = +Convertible_To_Rows.from that:Dictionary = vals = that.to_vector.map p-> Key_Value.Pair p.first p.second Convertible_To_Rows.Value vals.length (vals.get _) ["Key", "Value"] diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso index 84cfa30e6a7..c32b7fbeaf6 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso @@ -755,7 +755,7 @@ type Truncated_Column_Names ## PRIVATE Indicates that some column names were truncated to fit the maximum length supported by the backend. - Warning (names_map : Map Text Text) + Warning (names_map : Dictionary Text Text) ## PRIVATE Get the original column names. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso index d9e6743d7d3..775facd9f13 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Expand_Objects_Helpers.enso @@ -97,47 +97,46 @@ create_table_from_objects (value : Convertible_To_Rows) (fields : Vector | Nothi Java_Problems.with_problem_aggregator Problem_Behavior.Report_Warning java_problem_aggregator-> preset_fields = fields.is_nothing.not - initial_map = if preset_fields.not then Map.empty else - Map.from_vector (fields.map field_name-> [field_name, Java_Exports.make_inferred_builder len java_problem_aggregator]) error_on_duplicates=False + initial_dict = if preset_fields.not then Dictionary.empty else + Dictionary.from_vector (fields.map field_name-> [field_name, Java_Exports.make_inferred_builder len java_problem_aggregator]) error_on_duplicates=False # This is used to ensure that field names in the resulting table are in the order they were encountered. discovered_field_names = Builder.new - builder_map = case preset_fields of + builder_dict = case preset_fields of # Just get the queried keys from each object. True -> 0.up_to len . each idx-> v = (value.getter idx).to Convertible_To_Columns - initial_map.each_with_key field_name-> builder-> + initial_dict.each_with_key field_name-> builder-> builder.append (v.getter field_name) - initial_map + initial_dict # In this mode we are discovering the key set as we go. False -> - 0.up_to len . fold initial_map current_map-> idx-> + 0.up_to len . fold initial_dict current_dict-> idx-> v = (value.getter idx).to Convertible_To_Columns - v.field_names.fold current_map inner_current_map-> f-> - existing_builder = inner_current_map.get f Nothing + v.field_names.fold current_dict inner_current_dict-> f-> + existing_builder = inner_current_dict.get f Nothing builder = existing_builder.if_nothing <| discovered_field_names.append f Java_Exports.make_inferred_builder len java_problem_aggregator builder.fillUpToSize idx builder.append (v.getter f) - new_map = if existing_builder.is_nothing.not then inner_current_map else - inner_current_map.insert f builder - new_map + if existing_builder.is_nothing.not then inner_current_dict else + inner_current_dict.insert f builder # Seal all builders and create columns - column_map = builder_map.map_with_key name-> builder-> + column_dict = builder_dict.map_with_key name-> builder-> builder.fillUpToSize len Column.from_storage name builder.seal - column_map.if_not_error <| + column_dict.if_not_error <| # Create a vector of columns, preserving the original order if it was specified. columns = case preset_fields of - True -> fields.distinct.map column_map.get + True -> fields.distinct.map column_dict.get False -> if discovered_field_names.is_empty then Error.throw (Illegal_Argument.Error "Unable to generate column names as all inputs had no fields.") else - discovered_field_names.to_vector.map column_map.get + discovered_field_names.to_vector.map column_dict.get Table.new columns diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Fan_Out.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Fan_Out.enso index 05a98904a69..8664ce9d600 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Fan_Out.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Fan_Out.enso @@ -172,7 +172,7 @@ fan_out_to_rows_and_columns_fixed input_storage function at_least_one_row:Boolea fan_out_to_rows_and_columns_dynamic : Any -> (Any -> Vector (Vector Any)) -> Boolean -> (Any -> Text) -> (Integer -> Any) -> Problem_Builder -> Vector fan_out_to_rows_and_columns_dynamic input_storage function at_least_one_row column_names_for_row column_builder problem_builder = # Accumulates the outputs of the function. - column_map = Ref.new Map.empty + column_dict = Ref.new Dictionary.empty output_column_builders = Builder.new # Guess that most of the time, we'll get at least one value for each input. @@ -180,7 +180,7 @@ fan_out_to_rows_and_columns_dynamic input_storage function at_least_one_row colu # Column Builder add function add_column n current_length = - column_map.put (column_map.get.insert n output_column_builders.length) + column_dict.put (column_dict.get.insert n output_column_builders.length) builder = column_builder num_input_rows builder.appendNulls current_length output_column_builders.append builder @@ -200,11 +200,11 @@ fan_out_to_rows_and_columns_dynamic input_storage function at_least_one_row colu # Add any missing columns. row_column_names.each n-> - if column_map.get.contains_key n . not then + if column_dict.get.contains_key n . not then add_column n order_mask_positions.length # Append each group of values to the builder. - current_columns = column_map.get + current_columns = column_dict.get output_values.each row_unchecked-> row = uniform_length row_column_names.length row_unchecked problem_builder row_column_names.each_with_index i->n-> @@ -220,7 +220,7 @@ fan_out_to_rows_and_columns_dynamic input_storage function at_least_one_row colu repeat_each output_values.length <| order_mask_positions.append i # Build the output column - output_columns = column_map.get.to_vector.sort on=_.second . map pair-> + output_columns = column_dict.get.to_vector.sort on=_.second . map pair-> Column.from_storage pair.first (output_column_builders.at pair.second . seal) [output_columns, order_mask_positions] diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Lookup_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Lookup_Helpers.enso index 9c8eef4fcb6..1f09b59273e 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Lookup_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Lookup_Helpers.enso @@ -50,7 +50,7 @@ prepare_columns_for_lookup base_table lookup_table key_columns_selector add_new_ problems_to_add = Builder.new key_columns.if_not_error <| lookup_table_key_columns.if_not_error <| - key_set = Set.from_vector key_columns + key_set = Hashset.from_vector key_columns my_updated_columns = base_table.columns.map on_problems=No_Wrap base_column-> base_column_name = base_column.name is_key = key_set.contains base_column_name @@ -67,7 +67,7 @@ prepare_columns_for_lookup base_table lookup_table key_columns_selector add_new_ Nothing -> Lookup_Column.Keep_Column base_column _ -> merge_columns base_column lookup_column allow_unmatched_rows - my_column_set = Set.from_vector base_table.column_names + my_column_set = Hashset.from_vector base_table.column_names extra_columns = lookup_table.columns.filter col-> is_new = my_column_set.contains col.name . not is_new diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Replace_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Replace_Helpers.enso index 6fb9591be9c..8adeffa0313 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Replace_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Replace_Helpers.enso @@ -10,7 +10,7 @@ import project.Value_Type.By_Type from project.Errors import Missing_Input_Columns, No_Such_Column, Non_Unique_Key, Unmatched_Rows_In_Lookup ## PRIVATE -replace : Table -> (Table | Map) -> (Text | Integer | By_Type | Vector (Text | Integer | By_Type)) -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup +replace : Table -> (Table | Dictionary) -> (Text | Integer | By_Type | Vector (Text | Integer | By_Type)) -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup replace base_table lookup_table columns:(Text | Integer | By_Type | Vector (Text | Integer | By_Type)) from_column:(Text | Integer | Nothing)=Nothing to_column:(Text | Integer | Nothing)=Nothing allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning = case columns of _ : Vector -> @@ -20,8 +20,8 @@ replace base_table lookup_table columns:(Text | Integer | By_Type | Vector (Text _ -> column = columns case lookup_table of - _ : Map -> - if from_column.is_nothing.not || to_column.is_nothing.not then Error.throw (Illegal_Argument.Error "If a Map is provided as the lookup_table, then from_column and to_column should not also be specified.") else + _ : Dictionary -> + if from_column.is_nothing.not || to_column.is_nothing.not then Error.throw (Illegal_Argument.Error "If a Dictionary is provided as the lookup_table, then from_column and to_column should not also be specified.") else handle_empty_lookup_table ~action = if lookup_table.is_empty.not then action else ## If the lookup table is empty but the base table is @@ -33,7 +33,7 @@ replace base_table lookup_table columns:(Text | Integer | By_Type | Vector (Text a_key_value = base_table.at column . at 0 Error.throw (Unmatched_Rows_In_Lookup.Error [a_key_value]) handle_empty_lookup_table <| - base_table.replace (base_table.make_table_from_map lookup_table 'from' 'to') column 'from' 'to' allow_unmatched_rows=allow_unmatched_rows on_problems=on_problems + base_table.replace (base_table.make_table_from_dictionary lookup_table 'from' 'to') column 'from' 'to' allow_unmatched_rows=allow_unmatched_rows on_problems=on_problems _ -> from_column_resolved = from_column.if_nothing 0 to_column_resolved = to_column.if_nothing 1 @@ -52,7 +52,7 @@ replace base_table lookup_table columns:(Text | Integer | By_Type | Vector (Text ## Create a lookup table with just `to_column` and `from_column`, renamed to match the base table's `column` and its duplicate, respectively. - lookup_table_renamed = selected_lookup_columns . rename_columns (Map.from_vector [[from_column_resolved, duplicate_key_column_name], [to_column_resolved, column]]) + lookup_table_renamed = selected_lookup_columns . rename_columns (Dictionary.from_vector [[from_column_resolved, duplicate_key_column_name], [to_column_resolved, column]]) warn_if_empty result_table = if lookup_table_renamed.row_count != 0 then result_table else Warning.attach (Empty_Error.Error "lookup_table") result_table diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso index 7665a8336d5..08059b39a9c 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Split_Tokenize.enso @@ -91,7 +91,7 @@ regex_to_column_names pattern original_column_name = group_nums_to_names = pattern.group_nums_to_names unnamed_group_numbers = 1.up_to pattern.group_count . filter i-> group_nums_to_names.contains_key i . not - group_number_to_column_name_suffix = Map.from_vector <| unnamed_group_numbers.zip (0.up_to unnamed_group_numbers.length) + group_number_to_column_name_suffix = Dictionary.from_vector <| unnamed_group_numbers.zip (0.up_to unnamed_group_numbers.length) Vector.new (pattern.group_count-1) i-> # explicit groups start at 1 diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso index f97c754d241..8331544f576 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso @@ -112,7 +112,7 @@ type Table_Column_Helper remove_columns self (selectors:(Text | Integer | Regex | Vector)) (case_sensitivity:Case_Sensitivity) (error_on_missing_columns:Boolean) (on_problems:Problem_Behavior) = problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns selection = self.select_columns_helper selectors case_sensitivity False problem_builder - selected_names = Map.from_vector (selection.map column-> [column.name, True]) + selected_names = Dictionary.from_vector (selection.map column-> [column.name, True]) result = self.columns.filter column-> should_be_removed = selected_names.get column.name False should_be_removed.not @@ -160,7 +160,7 @@ type Table_Column_Helper problem_builder = Problem_Builder.new error_on_missing_columns=error_on_missing_columns selection = self.select_columns_helper selectors case_sensitivity True problem_builder problem_builder.attach_problems_before on_problems <| - selected_names = Map.from_vector (selection.map column-> [column.name, True]) + selected_names = Dictionary.from_vector (selection.map column-> [column.name, True]) other_columns = self.columns.filter column-> is_selected = selected_names.get column.name False is_selected.not @@ -203,8 +203,8 @@ type Table_Column_Helper _ -> [selectors] selected_columns = vector.map resolve_selector . flatten if reorder then selected_columns.distinct on=_.name else - map = Map.from_vector (selected_columns.map column-> [column.name, True]) error_on_duplicates=False - self.columns.filter column-> map.contains_key column.name + dict = Dictionary.from_vector (selected_columns.map column-> [column.name, True]) error_on_duplicates=False + self.columns.filter column-> dict.contains_key column.name ## PRIVATE A helper function which selects a single column from the table. @@ -289,14 +289,14 @@ type Table_Column_Helper A helper function which takes a Table like object and a Table for a name mapping and returns a new Table with the columns renamed according to the mapping. -read_name_map_from_table : Table -> Vector | Map ! Illegal_Argument -read_name_map_from_table column_map:Table = case column_map.column_count of +read_name_mapping_from_table : Table -> Vector | Dictionary ! Illegal_Argument +read_name_mapping_from_table column_map:Table = case column_map.column_count of 1 -> col = column_map.first_column if col.value_type.is_text then col.to_vector else Error.throw (Illegal_Argument.Error "Expected a table with one or two columns of text values.") 2 -> - if column_map.first_column.value_type.is_text && (column_map.at 1).value_type.is_text then Map.from_vector column_map.rows else + if column_map.first_column.value_type.is_text && (column_map.at 1).value_type.is_text then Dictionary.from_vector column_map.rows else Error.throw (Illegal_Argument.Error "Expected a table with one or two columns of text values.") _ -> Error.throw (Illegal_Argument.Error "Expected a table with one or two columns of text values.") @@ -322,9 +322,9 @@ read_name_map_from_table column_map:Table = case column_map.column_count of operation. By default, a warning is issued, but the operation proceeds. If set to `Report_Error`, the operation fails with a dataflow error. If set to `Ignore`, the operation proceeds without errors or warnings. -rename_columns : Column_Naming_Helper -> Vector -> Map (Text | Integer | Regex) Text | Vector Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Map Text Text -rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) (mapping:(Map | Vector)) (case_sensitivity:Case_Sensitivity) (error_on_missing_columns:Boolean) (on_problems:Problem_Behavior) = - ## Convert Vector of Pairs to Map +rename_columns : Column_Naming_Helper -> Vector -> Dictionary (Text | Integer | Regex) Text | Vector Text -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Dictionary Text Text +rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) (mapping:(Dictionary | Vector)) (case_sensitivity:Case_Sensitivity) (error_on_missing_columns:Boolean) (on_problems:Problem_Behavior) = + ## Convert Vector of Pairs to Dictionary is_vec_pairs = mapping.is_a Vector && mapping.length > 0 && (mapping.first.is_a Text . not) case is_vec_pairs of True -> @@ -333,8 +333,8 @@ rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) is_valid_key k = k.is_a Integer || k.is_a Text || k.is_a Regex all_pairs = mapping.all p-> (is_valid_row p) && p.length == 2 && (is_valid_key p.first) && p.second.is_a Text if all_pairs.not then Error.throw (Illegal_Argument.Error "mapping is not a Vector of old name to new name.") else - ## Attempt to treat as Map - map = Map.from_vector mapping error_on_duplicates=False + ## Attempt to treat as Dictionary + map = Dictionary.from_vector mapping error_on_duplicates=False if map.length == mapping.length then rename_columns naming_helper internal_columns map case_sensitivity error_on_missing_columns on_problems else duplicates = mapping.duplicates on=_.first . map p->p.first.to_text . distinct duplicate_text = if duplicates.length < 5 then duplicates.to_vector . join ", " else @@ -356,7 +356,7 @@ rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) problem_builder.report_other_warning (Too_Many_Column_Names_Provided.Error (vec.drop (..First col_count))) vec.take (..First col_count) internal_columns.take good_names.length . zip good_names - _ : Map -> + _ : Dictionary -> resolve_rename selector replacement = case selector of ix : Integer -> if is_index_valid internal_columns.length ix then [Pair.new (internal_columns.at ix) replacement] else problem_builder.report_oob_indices [ix] @@ -378,7 +378,7 @@ rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) naming_helper.validate_many_column_names all_new_names <| ## Resolves actual new names for renamed columns. If a column received ambiguous new names, an error is raised. - name_map = columns_with_new_names.fold Map.empty current-> pair-> + name_dict = columns_with_new_names.fold Dictionary.empty current-> pair-> old_name = pair.first.name case current.contains_key old_name of False -> current.insert old_name pair.second @@ -387,12 +387,12 @@ rename_columns (naming_helper : Column_Naming_Helper) (internal_columns:Vector) Error.throw (Ambiguous_Column_Rename.Error old_name new_names) ## Renamed names take precedence, so we first deduplicate those. - resolved_name_map = name_map.map unique.make_unique + resolved_name_dict = name_dict.map unique.make_unique ## Then we ensure that the names of not-renamed columns are also unique and return the effective column names for each column. - not_renamed = internal_columns.filter c-> resolved_name_map.contains_key c.name . not - new_column_names = not_renamed.fold resolved_name_map current-> column-> + not_renamed = internal_columns.filter c-> resolved_name_dict.contains_key c.name . not + new_column_names = not_renamed.fold resolved_name_dict current-> column-> new_name = unique.make_unique column.name current.insert column.name new_name @@ -443,7 +443,7 @@ select_indices_reordering vector indices = The elements are returned in the same order as they appeared in the original vector. select_indices_preserving_order vector indices = - indices_to_keep = Map.from_vector (indices.map i-> [i, True]) + indices_to_keep = Dictionary.from_vector (indices.map i-> [i, True]) vector.filter_with_index ix-> _-> indices_to_keep.get ix False diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso index 13f2320a539..16ac675242e 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso @@ -98,10 +98,10 @@ type Unique_Name_Strategy ## PRIVATE A mapping of original names to their truncated counterpart. - truncated_names : Map Text Text + truncated_names : Dictionary Text Text truncated_names self = entries = Vector.from_polyglot_array self.deduplicator.getTruncatedNames - Map.from_vector <| entries.map e-> [e.getLeft, e.getRight] + Dictionary.from_vector <| entries.map e-> [e.getLeft, e.getRight] ## PRIVATE ADVANCED diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Match_Columns.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Match_Columns.enso index b240105bf79..7cab62bcdcb 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Match_Columns.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Match_Columns.enso @@ -142,7 +142,7 @@ type Column_Set ## PRIVATE Returns a map indicating in how many tables did a column with a given name appear. find_column_counts tables = - tables.fold Map.empty current->table-> + tables.fold Dictionary.empty current->table-> table.columns.fold current counts-> column-> name=column.name new_count = counts.get name 0 + 1 @@ -153,7 +153,7 @@ find_column_counts tables = starting from the first table. distinct_columns_in_appearance_order tables = Vector.build names_builder-> - tables.fold Map.empty current-> table-> + tables.fold Dictionary.empty current-> table-> table.columns.fold current seen_names-> column-> name = column.name if seen_names.contains_key name then seen_names else diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Row.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Row.enso index 041b8ab03f5..1fec02f336c 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Row.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Row.enso @@ -53,11 +53,11 @@ type Row ## GROUP Standard.Base.Conversions ICON convert - Gets the row as a Map. - to_map : Map - to_map self = + Gets the row as a Dictionary. + to_dictionary : Dictionary + to_dictionary self = pairs = self.table.column_names.map n-> [n, self.get n] - Map.from_vector pairs + Dictionary.from_vector pairs ## PRIVATE Converts this row into a JS_Object. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso index ddd7f5ec1e9..e3df2077656 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso @@ -680,17 +680,17 @@ type Table > Example Rename the "Alpha" column to "Beta" - table.rename_columns (Map.from_vector [["Alpha", "Beta"]]) + table.rename_columns (Dictionary.from_vector [["Alpha", "Beta"]]) > Example Rename the last column to "LastColumn" - table.rename_columns (Map.from_vector [[-1, "LastColumn"]]) + table.rename_columns (Dictionary.from_vector [[-1, "LastColumn"]]) > Example Rename the "Alpha" column to "Beta" and last column to "LastColumn" - table.rename_columns (Map.from_vector [["Alpha", "Beta"], [-1, "LastColumn"]]) + table.rename_columns (Dictionary.from_vector [["Alpha", "Beta"], [-1, "LastColumn"]]) > Example Rename the first column to "FirstColumn" @@ -705,12 +705,12 @@ type Table > Example For all columns starting with the prefix `name=`, replace it with `key:`. - table.rename_columns (Map.from_vector [["name=(.*)".to_regex, "key:$1"]]) + table.rename_columns (Dictionary.from_vector [["name=(.*)".to_regex, "key:$1"]]) @column_map Widget_Helpers.make_rename_name_vector_selector - rename_columns : Map (Text | Integer | Regex) Text | Vector Text | Vector Vector -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Ambiguous_Column_Rename | Too_Many_Column_Names_Provided | Invalid_Column_Names | Duplicate_Output_Column_Names - rename_columns self (column_map:(Table | Map | Vector)=["Column"]) (case_sensitivity:Case_Sensitivity=..Default) (error_on_missing_columns:Boolean=True) (on_problems:Problem_Behavior=..Report_Warning) = case column_map of + rename_columns : Table | Dictionary (Text | Integer | Regex) Text | Vector Text | Vector Vector -> Case_Sensitivity -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Ambiguous_Column_Rename | Too_Many_Column_Names_Provided | Invalid_Column_Names | Duplicate_Output_Column_Names + rename_columns self (column_map:(Table | Dictionary | Vector)=["Column"]) (case_sensitivity:Case_Sensitivity=..Default) (error_on_missing_columns:Boolean=True) (on_problems:Problem_Behavior=..Report_Warning) = case column_map of _ : Table -> - resolved = Table_Helpers.read_name_map_from_table column_map + resolved = Table_Helpers.read_name_mapping_from_table column_map self.rename_columns resolved case_sensitivity error_on_missing_columns on_problems _ -> new_names = Table_Helpers.rename_columns self.column_naming_helper self.columns column_map case_sensitivity error_on_missing_columns on_problems @@ -1123,9 +1123,9 @@ type Table no_columns_problem_behavior = case error_on_missing_columns of True -> Problem_Behavior.Report_Error False -> on_problems - no_columns_problem_behavior.attach_problem_before No_Input_Columns_Selected Map.empty + no_columns_problem_behavior.attach_problem_before No_Input_Columns_Selected Dictionary.empty False -> - Map.from_vector <| selected_columns.map c-> [c.name, True] + Dictionary.from_vector <| selected_columns.map c-> [c.name, True] new_columns = self.columns.map on_problems=No_Wrap column-> if selected_column_names.contains_key column.name . not then column else Value_Type.expect_text column <| @@ -1222,9 +1222,9 @@ type Table no_columns_problem_behavior = case error_on_missing_columns of True -> Problem_Behavior.Report_Error False -> on_problems - no_columns_problem_behavior.attach_problem_before No_Input_Columns_Selected Map.empty + no_columns_problem_behavior.attach_problem_before No_Input_Columns_Selected Dictionary.empty False -> - Map.from_vector <| selected_columns.map c-> [c.name, True] + Dictionary.from_vector <| selected_columns.map c-> [c.name, True] new_columns = self.columns.map column-> if selected_column_names.contains_key column.name . not then column else column.format format locale @@ -1887,22 +1887,22 @@ type Table Warning.set result [] ## PRIVATE - A helper that creates a two-column table from a Map. + A helper that creates a two-column table from a Dictionary. - The keys of the `Map` become the first column, with name - `key_column_name`, and the values of the `Map` become the second column, - with name `value_column_name`. + The keys of the `Dictionary` become the first column, with name + `key_column_name`, and the values become the second column, with name + `value_column_name`. - For the in-memory database, the `Map` can be empty. For the database - backends, it must not be empty. + For the in-memory database, the `Dictionary` can be empty. For the + database backends, it must not be empty. Arguments: - - map: The `Map` to create the table from. + - dict: The `Dictionary` to create the table from. - key_column_name: The name to use for the first column. - value_column_name: The name to use for the second column. - make_table_from_map : Map Any Any -> Text -> Text -> Table - make_table_from_map self map key_column_name value_column_name = - keys_and_values = map.to_vector + make_table_from_dictionary : Dictionary Any Any -> Text -> Text -> Table + make_table_from_dictionary self dict key_column_name value_column_name = + keys_and_values = dict.to_vector self.make_table_from_vectors [keys_and_values.map .first, keys_and_values.map .second] [key_column_name, value_column_name] ## PRIVATE @@ -2283,8 +2283,8 @@ type Table @columns (Widget_Helpers.make_column_name_multi_selector add_regex=True add_by_type=True) @from_column Widget.Text_Input @to_column Widget.Text_Input - replace : (Table | Map) -> (Text | Integer | Regex | By_Type | Vector (Text | Integer | Regex | By_Type)) -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup - replace self lookup_table:(Table | Map) columns:(Text | Integer | Regex | By_Type | Vector (Text | Integer | Regex | By_Type)) from_column:(Text | Integer | Nothing)=Nothing to_column:(Text | Integer | Nothing)=Nothing allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning = + replace : (Table | Dictionary) -> (Text | Integer | Regex | By_Type | Vector (Text | Integer | Regex | By_Type)) -> (Text | Integer | Nothing) -> (Text | Integer | Nothing) -> Boolean -> Problem_Behavior -> Table ! Missing_Input_Columns | Non_Unique_Key | Unmatched_Rows_In_Lookup + replace self lookup_table:(Table | Dictionary) columns:(Text | Integer | Regex | By_Type | Vector (Text | Integer | Regex | By_Type)) from_column:(Text | Integer | Nothing)=Nothing to_column:(Text | Integer | Nothing)=Nothing allow_unmatched_rows:Boolean=True on_problems:Problem_Behavior=..Report_Warning = Replace_Helpers.replace self lookup_table columns from_column to_column allow_unmatched_rows on_problems ## ALIAS join by row position @@ -2566,7 +2566,7 @@ type Table id_columns = columns_helper.select_columns_helper key_columns Case_Sensitivity.Default False problem_builder - selected_names = Map.from_vector (id_columns.map column-> [column.name, True]) + selected_names = Dictionary.from_vector (id_columns.map column-> [column.name, True]) data = columns_helper.internal_columns.filter column->(selected_names.get column.name False . not) java_data = data.map c->c.java_column @@ -3183,13 +3183,6 @@ concat_columns column_set all_tables result_type result_row_count needs_cast on_ sealed_storage = storage_builder.seal Column.from_storage column_set.name sealed_storage -## PRIVATE - A helper that creates a two-column table from a map. -map_to_lookup_table : Map Any Any -> Text -> Text -> Table -map_to_lookup_table map key_column value_column = - keys_and_values = map.to_vector - Table.new [[key_column, keys_and_values.map .first], [value_column, keys_and_values.map .second]] - ## PRIVATE Conversion method to a Table from a Column. Table.from (that:Column) = that.to_table diff --git a/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso b/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso index 13f31c6cfc4..732b4d28335 100644 --- a/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso +++ b/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso @@ -98,7 +98,7 @@ print_single_result (test_result : Test_Result) (config : Suite_Config) = print_report : Vector Test_Result -> Suite_Config -> (StringBuilder | Nothing) -> Nothing print_report (test_results : Vector Test_Result) (config : Suite_Config) (builder : (StringBuilder | Nothing)) = distinct_group_names = test_results.map (_.group_name) . distinct - results_per_group = distinct_group_names.fold Map.empty acc-> group_name-> + results_per_group = distinct_group_names.fold Dictionary.empty acc-> group_name-> group_results = test_results.filter res-> res.group_name == group_name assert (group_results.length > 0) diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso index 1ac1cc7bfc0..b3d05fa6489 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso @@ -173,7 +173,7 @@ limit_data limit data = case limit of bounds = case data.fold_with_index (Extreme.Value first first first first) update_extreme of Extreme.Value min_x max_x min_y max_y -> [min_x, max_x, min_y, max_y] _ -> [] - extreme = Map.from_vector bounds error_on_duplicates=False . values + extreme = Dictionary.from_vector bounds error_on_duplicates=False . values if limit <= extreme.length then extreme.take (..First limit) else extreme + data.take (..Sample (limit - extreme.length)) diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso index fa07daa5bb8..0e82180fc97 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso @@ -27,9 +27,9 @@ prepare_visualization y max_rows=1000 = result = case x of _ : Vector -> make_json_for_vector x max_rows _ : Array -> prepare_visualization x.to_vector max_rows - _ : Map -> make_json_for_map x max_rows + _ : Dictionary -> make_json_for_dictionary x max_rows _ : JS_Object -> make_json_for_js_object x max_rows - _ : Row -> make_json_for_map x.to_map max_rows "column" + _ : Row -> make_json_for_dictionary x.to_dictionary max_rows "column" _ : Column -> prepare_visualization x.to_table max_rows _ : Table -> dataframe = x.take max_rows @@ -98,7 +98,7 @@ make_json_for_object_matrix current vector idx=0 = if idx == vector.length then _ : Date_Time -> False _ : Duration -> False _ : Period -> False - _ : Map -> + _ : Dictionary -> pairs = row.keys.map k-> [k.to_text, make_json_for_value (row.get k)] JS_Object.from_pairs pairs _ : Row -> @@ -115,13 +115,13 @@ make_json_for_object_matrix current vector idx=0 = if idx == vector.length then @Tail_Call make_json_for_object_matrix current vector idx+1 ## PRIVATE - Render Map to JSON -make_json_for_map : Map -> Integer -> Text -> JS_Object -make_json_for_map map max_items key_name="key" = + Render Dictionary to JSON +make_json_for_dictionary : Dictionary -> Integer -> Text -> JS_Object +make_json_for_dictionary dict max_items key_name="key" = header = ["header", [key_name, "value"]] - all_rows = ["all_rows_count", map.size] - map_vector = Warning.clear (map.to_vector.take max_items) - mapped = map_vector . map p-> [p.first.to_text, make_json_for_value p.second] + all_rows = ["all_rows_count", dict.size] + as_vector = Warning.clear (dict.to_vector.take max_items) + mapped = as_vector . map p-> [p.first.to_text, make_json_for_value p.second] data = ["data", [mapped.map .first, mapped.map .second]] JS_Object.from_pairs [header, data, all_rows, ["type", "Map"]] @@ -187,7 +187,7 @@ make_json_for_value val level=0 = case val of prepared = if val.length > 5 then truncated + ["… " + (val.length - 5).to_text+ " items"] else truncated "[" + (prepared.join ", ") + "]" _ : Array -> make_json_for_value val.to_vector level - _ : Map -> + _ : Dictionary -> if level != 0 then "{… "+val.size.to_text+" items}" else truncated = val.keys.take 5 . map k-> k.to_text + ": " + (make_json_for_value (val.get k) level+1).to_text prepared = if val.length > 5 then truncated + ["… " + (val.length - 5).to_text+ " items"] else truncated diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ConversionMethodTests.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ConversionMethodTests.java index 2f560f39850..ca317701e94 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ConversionMethodTests.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ConversionMethodTests.java @@ -64,12 +64,12 @@ public class ConversionMethodTests { String src = """ polyglot java import java.util.Map as Java_Map - import Standard.Base.Data.Map.Map + import Standard.Base.Data.Dictionary.Dictionary type Foo Mk_Foo data - Foo.from (that:Map) = Foo.Mk_Foo that + Foo.from (that:Dictionary) = Foo.Mk_Foo that main = jmap = Java_Map.of "A" 1 "B" 2 "C" 3 @@ -83,7 +83,7 @@ public class ConversionMethodTests { public void testDispatchOnJSMap() { String src = """ - import Standard.Base.Data.Map.Map + import Standard.Base.Data.Dictionary.Dictionary foreign js js_map = ''' let m = new Map() @@ -94,7 +94,7 @@ public class ConversionMethodTests { type Foo Mk_Foo data - Foo.from (that:Map) = Foo.Mk_Foo that + Foo.from (that:Dictionary) = Foo.Mk_Foo that main = Foo.from js_map . data . size diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/MetaObjectTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/MetaObjectTest.java index 95243782081..621dce9a01b 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/MetaObjectTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/MetaObjectTest.java @@ -285,66 +285,7 @@ main = Nothing .invokeMember(MethodNames.Module.EVAL_EXPRESSION, "sn"); var sb = new StringBuilder(); for (var v : g.allValues()) { - var simpleName = sn.execute(v).asString(); - if (v.isNumber()) { - var ok = - switch (simpleName) { - case "Integer", "Float" -> true; - default -> false; - }; - assertTrue("Unexpected simple name for number: " + simpleName, ok); - continue; - } - var meta = v.getMetaObject(); - var metaName = meta != null ? meta.getMetaSimpleName() : "null"; - if (!simpleName.equals(metaName)) { - if (v.isHostObject()) { - if (v.hasArrayElements()) { - assertEquals("Array", simpleName); - continue; - } - if (v.hasHashEntries()) { - assertEquals("Map", simpleName); - continue; - } - } - if (v.isString()) { - assertEquals("Text", simpleName); - continue; - } - if (v.isDuration()) { - assertEquals("Duration", simpleName); - continue; - } - if (v.isDate() && v.isTime()) { - assertEquals("Date_Time", simpleName); - continue; - } - if (v.isTimeZone()) { - assertEquals("Time_Zone", simpleName); - continue; - } - if (v.isDate()) { - assertEquals("Date", simpleName); - continue; - } - if (v.isTime()) { - assertEquals("Time_Of_Day", simpleName); - continue; - } - if (v.isNull()) { - assertEquals("Nothing", simpleName); - continue; - } - - sb.append("\n") - .append("Simple names shall be the same for ") - .append(v) - .append(" get_simple_type_name: ") - .append(simpleName) - .append(" getMetaSimpleName: ") - .append(metaName); - } + compareQualifiedNameOfValue(sn, v, sb); } if (!sb.isEmpty()) { var lines = sb.toString().lines().count() - 1; @@ -353,6 +294,77 @@ main = Nothing } } + private boolean compareQualifiedNameOfValue(Value sn, Value v, StringBuilder sb) { + var simpleName = sn.execute(v).asString(); + if (v.isNumber()) { + var ok = + switch (simpleName) { + case "Integer", "Float" -> true; + default -> false; + }; + assertTrue("Unexpected simple name for number: " + simpleName, ok); + return true; + } + var meta = v.getMetaObject(); + var metaName = meta != null ? meta.getMetaSimpleName() : "null"; + if (!simpleName.equals(metaName)) { + if (v.isHostObject()) { + if (v.hasArrayElements()) { + assertEquals("Array", simpleName); + return true; + } + if (v.hasHashEntries()) { + assertEquals("Dictionary", simpleName); + return true; + } + } + if (v.hasMembers() && v.getMember("__proto__") != null) { + if (v.hasHashEntries()) { + assertEquals("JavaScript hash map is called Map", "Map", metaName); + assertEquals( + "JavaScript hash map is seen as Dictionary by Enso", "Dictionary", simpleName); + return true; + } + } + if (v.isString()) { + assertEquals("Text", simpleName); + return true; + } + if (v.isDuration()) { + assertEquals("Duration", simpleName); + return true; + } + if (v.isDate() && v.isTime()) { + assertEquals("Date_Time", simpleName); + return true; + } + if (v.isTimeZone()) { + assertEquals("Time_Zone", simpleName); + return true; + } + if (v.isDate()) { + assertEquals("Date", simpleName); + return true; + } + if (v.isTime()) { + assertEquals("Time_Of_Day", simpleName); + return true; + } + if (v.isNull()) { + assertEquals("Nothing", simpleName); + return true; + } + sb.append("\n") + .append("Simple names shall be the same for ") + .append(v) + .append(" get_simple_type_name: ") + .append(simpleName) + .append(" getMetaSimpleName: ") + .append(metaName); + } + return false; + } + @Test public void compareQualifiedAndSimpleTypeNameForTypes() throws Exception { var g = generator(); diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ValuesGenerator.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ValuesGenerator.java index d457271924e..1c41d6ddff5 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ValuesGenerator.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/ValuesGenerator.java @@ -303,9 +303,13 @@ public final class ValuesGenerator { } public Value typeMap() { - return v("typeMap", """ - import Standard.Base.Data.Map.Map - """, "Map").type(); + return v( + "typeMap", + """ + import Standard.Base.Data.Dictionary.Dictionary + """, + "Dictionary") + .type(); } public Value typeWarning() { @@ -679,28 +683,28 @@ public final class ValuesGenerator { if (languages.contains(Language.ENSO)) { var imports = """ - import Standard.Base.Data.Map.Map + import Standard.Base.Data.Dictionary.Dictionary import Standard.Base.Nothing.Nothing """; for (var expr : List.of( - "Map.empty", - "Map.singleton Nothing Nothing", - "Map.singleton Nothing 'my_value'", - "Map.singleton 'my_value' Nothing", - "Map.singleton 1 1", - "Map.singleton 'C' 3", - "Map.singleton 'C' 43", - "Map.empty.insert 'A' 10 . insert 'B' 20", + "Dictionary.empty", + "Dictionary.singleton Nothing Nothing", + "Dictionary.singleton Nothing 'my_value'", + "Dictionary.singleton 'my_value' Nothing", + "Dictionary.singleton 1 1", + "Dictionary.singleton 'C' 3", + "Dictionary.singleton 'C' 43", + "Dictionary.empty.insert 'A' 10 . insert 'B' 20", // ((int) 'A') + ((int) 'B') = 131 ; codePoint(131) = \203 - "Map.singleton '\203' 30", - "Map.singleton Map.empty 1", - "Map.singleton Map.empty Map.empty", - "Map.empty.insert 1 1 . insert 2 2", - "Map.empty.insert Nothing 'val' . insert 'key' 42", - "Map.empty.insert 'A' 1 . insert 'B' 2 . insert 'C' 3", - "Map.empty.insert 'C' 3 . insert 'B' 2 . insert 'A' 1")) { - collect.add(v("maps-" + expr, imports, expr, "Map").type()); + "Dictionary.singleton '\203' 30", + "Dictionary.singleton Dictionary.empty 1", + "Dictionary.singleton Dictionary.empty Dictionary.empty", + "Dictionary.empty.insert 1 1 . insert 2 2", + "Dictionary.empty.insert Nothing 'val' . insert 'key' 42", + "Dictionary.empty.insert 'A' 1 . insert 'B' 2 . insert 'C' 3", + "Dictionary.empty.insert 'C' 3 . insert 'B' 2 . insert 'A' 1")) { + collect.add(v("maps-" + expr, imports, expr, "Dictionary").type()); } } if (languages.contains(Language.JAVA)) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java index ba6a633674e..dfcf357a1c3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java @@ -358,7 +358,10 @@ public abstract class InvokeConversionNode extends BaseNode { @Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) { Function function = conversionResolverNode.expectNonNull( - thatMap, extractType(self), EnsoContext.get(this).getBuiltins().map(), conversion); + thatMap, + extractType(self), + EnsoContext.get(this).getBuiltins().dictionary(), + conversion); return invokeFunctionNode.execute(function, frame, state, arguments); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index 57e4b2ba9bb..ead711103a7 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -637,7 +637,7 @@ public abstract class InvokeMethodNode extends BaseNode { @Shared("warnings") @CachedLibrary(limit = "10") WarningsLibrary warnings, @Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) { var ctx = EnsoContext.get(this); - var hashMapType = ctx.getBuiltins().map(); + var hashMapType = ctx.getBuiltins().dictionary(); var function = methodResolverNode.expectNonNull(self, hashMapType, symbol); arguments[0] = self; return invokeFunctionNode.execute(function, frame, state, arguments); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java index 4955e245786..7224e103e62 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java @@ -104,7 +104,7 @@ public final class Builtins { private final Builtin text; private final Builtin array; private final Builtin vector; - private final Builtin map; + private final Builtin dictionary; private final Builtin dataflowError; private final Builtin ref; private final Builtin managedResource; @@ -155,7 +155,7 @@ public final class Builtins { text = builtins.get(Text.class); array = builtins.get(Array.class); vector = builtins.get(Vector.class); - map = builtins.get(org.enso.interpreter.node.expression.builtin.Map.class); + dictionary = builtins.get(org.enso.interpreter.node.expression.builtin.Dictionary.class); dataflowError = builtins.get(org.enso.interpreter.node.expression.builtin.Error.class); ref = builtins.get(Ref.class); managedResource = builtins.get(ManagedResource.class); @@ -691,8 +691,8 @@ public final class Builtins { return vector.getType(); } - public Type map() { - return map.getType(); + public Type dictionary() { + return dictionary.getType(); } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMap.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMap.java index 3598a6795db..076dbbebb0b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMap.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMap.java @@ -35,7 +35,7 @@ import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; */ @ExportLibrary(TypesLibrary.class) @ExportLibrary(InteropLibrary.class) -@Builtin(stdlibName = "Standard.Base.Data.Map.Map", name = "Map") +@Builtin(stdlibName = "Standard.Base.Data.Dictionary.Dictionary", name = "Dictionary") public final class EnsoHashMap implements EnsoObject { private final EnsoHashMapBuilder mapBuilder; private final int generation; @@ -150,7 +150,7 @@ public final class EnsoHashMap implements EnsoObject { @ExportMessage(library = TypesLibrary.class) Type getType(@Bind("$node") Node node) { - return EnsoContext.get(node).getBuiltins().map(); + return EnsoContext.get(node).getBuiltins().dictionary(); } @ExportMessage @@ -160,7 +160,7 @@ public final class EnsoHashMap implements EnsoObject { @ExportMessage Type getMetaObject(@Bind("$node") Node node) { - return EnsoContext.get(node).getBuiltins().map(); + return EnsoContext.get(node).getBuiltins().dictionary(); } @ExportMessage diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapContainsKeyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapContainsKeyNode.java index 05212ca524b..98a9fe39516 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapContainsKeyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapContainsKeyNode.java @@ -9,7 +9,7 @@ import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "contains_key", description = """ diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java index 1c72fa9f793..414bdae224c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapGetNode.java @@ -19,11 +19,11 @@ import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.state.State; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "get_builtin", description = """ - Gets a value from the map on the specified key, or the given default. + Gets a value from the dictionary on the specified key, or the given default. """, autoRegister = false, inlineable = true) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java index 6f64ed98b2c..4111414eec0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java @@ -18,7 +18,7 @@ import org.enso.interpreter.runtime.data.text.Text; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "insert", description = """ diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java index 53a311a09ac..17d7705b598 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java @@ -20,7 +20,7 @@ import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.DataflowError; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "remove_builtin", description = """ Removes an entry from this map specified with the key. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapSizeNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapSizeNode.java index bfed0dca68c..4cf6f794d8a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapSizeNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapSizeNode.java @@ -12,7 +12,7 @@ import org.enso.interpreter.runtime.data.text.Text; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "size", description = "Returns the number of entries in this hash map", autoRegister = false) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToTextNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToTextNode.java index ec00f348769..694554819ce 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToTextNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToTextNode.java @@ -13,7 +13,7 @@ import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.EnsoContext; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "to_text", description = """ Returns text representation of this hash map diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToVectorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToVectorNode.java index 4c3c7bd57c3..993f1739493 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToVectorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapToVectorNode.java @@ -18,7 +18,7 @@ import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( - type = "Map", + type = "Dictionary", name = "to_vector", description = """ diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/library/dispatch/TypeOfNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/library/dispatch/TypeOfNode.java index b3d57a56aa6..a8393c9a279 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/library/dispatch/TypeOfNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/library/dispatch/TypeOfNode.java @@ -114,7 +114,7 @@ public abstract class TypeOfNode extends Node { @Specialization(guards = {"type.isMap()"}) Type doPolygotMap(Interop type, Object value) { - return EnsoContext.get(this).getBuiltins().map(); + return EnsoContext.get(this).getBuiltins().dictionary(); } @Specialization(guards = {"type.isString()"}) diff --git a/test/AWS_Tests/src/S3_Spec.enso b/test/AWS_Tests/src/S3_Spec.enso index 5c771c8d114..da1369bac9e 100644 --- a/test/AWS_Tests/src/S3_Spec.enso +++ b/test/AWS_Tests/src/S3_Spec.enso @@ -169,7 +169,7 @@ add_specs suite_builder = suite_builder.group "S3.head (bucket)" pending=api_pending group_builder-> group_builder.specify "should be able to head a bucket" <| - S3.head bucket_name credentials=test_credentials . should_be_a Map + S3.head bucket_name credentials=test_credentials . should_be_a Dictionary S3.head not_a_bucket_name credentials=test_credentials . should_fail_with S3_Bucket_Not_Found suite_builder.group "S3.read_bucket" pending=api_pending group_builder-> diff --git a/test/Base_Tests/src/Data/Dictionary_Spec.enso b/test/Base_Tests/src/Data/Dictionary_Spec.enso new file mode 100644 index 00000000000..a5bc9fae4fd --- /dev/null +++ b/test/Base_Tests/src/Data/Dictionary_Spec.enso @@ -0,0 +1,633 @@ +from Standard.Base import all +import Standard.Base.Errors.Illegal_Argument.Illegal_Argument +import Standard.Base.Errors.No_Such_Key.No_Such_Key + +from Standard.Test import all + +polyglot java import java.util.Map as JavaMap +polyglot java import org.enso.base.file_system.File_Utils + +## Type that violates reflexivity +type My_Nan + Value comment:Text + +type My_Nan_Comparator + compare _ _ = Nothing + hash _ = 0 + +Comparable.from (_:My_Nan) = My_Nan_Comparator + +type My_Key + Value hash_code:Integer value:Text idx:Integer + +type My_Key_Comparator + # Comparison ignores idx field + compare x y = + if x.hash_code != y.hash_code then Nothing else + if x.value == y.value then Ordering.Equal else Nothing + + hash x = x.hash_code + +Comparable.from (_:My_Key) = My_Key_Comparator + + +foreign js js_str str = """ + return new String(str) + +foreign js js_null = """ + return null + +foreign js js_empty_dict = """ + return new Map() + +foreign python py_empty_dict = """ + return {} + +foreign js js_dict_from_vec vec = """ + dict = new Map() + for (let i = 0; i < vec.length; i += 2) { + dict.set(vec[i], vec[i+1]) + } + return dict + +foreign python py_none = """ + return None + +foreign python py_dict_from_vec vec = """ + d = {} + for i in range(0, len(vec), 2): + d[vec[i]] = vec[i + 1] + return d + +foreign python py_dict_from_map map = """ + d = dict() + for key in map.__iter__(): + d[key] = map[key] + return d + +foreign python py_vec_from_map map = """ + vec = [] + for key in map.__iter__(): + value = map[key] + vec.append([key, value]) + return vec + +# Should throw error - updating immutable map from Enso +foreign python py_update_dict map key val = """ + map[key] = val + +foreign python py_wrapper obj = """ + class MyClass: + def __init__(self, obj): + self.data = obj + return MyClass(obj) + +pending_python_missing = if Polyglot.is_language_installed "python" then Nothing else "Can't run Python tests, Python is not installed." + +type Child + Value data + +type Parent + Value child + +type GrandParent + Value parent + +add_specs suite_builder = + languages = Vector.build builder-> + builder . append ["Enso", _-> Dictionary.empty, Nothing] + builder . append ["Java", _-> JavaMap.of, Nothing] + builder . append ["JavaScript", _-> js_empty_dict, Nothing] + builder . append ["Python", _-> py_empty_dict, pending_python_missing] + languages.each entry-> + lang = entry.get 0 + empty_dict_fn = entry.get 1 + pending = entry.get 2 + add_common_specs suite_builder lang pending empty_dict_fn + + suite_builder.group "Enso Dictionaries" group_builder-> + group_builder.specify "should use proper hash code for keys" <| + single_key_dict key = Dictionary.singleton key 42 + grand_parent_1 = GrandParent.Value (Parent.Value (Child.Value 2)) + grand_parent_2 = GrandParent.Value (Parent.Value (Child.Value 2.0)) + + (single_key_dict 2 . at 2.0) . should_equal 42 + (single_key_dict -2 . at -2.0) . should_equal 42 + (single_key_dict 'ś' . at 's\u0301') . should_equal 42 + (single_key_dict 's\u0301' . at 'ś') . should_equal 42 + (single_key_dict 'éabc' . at 'e\u0301abc') . should_equal 42 + (single_key_dict 'e\u0301abc' . at 'éabc') . should_equal 42 + (single_key_dict grand_parent_1 . at grand_parent_2) . should_equal 42 + (single_key_dict (Json.parse '{"a": 1}') . at (Json.parse '{"a": 1}')) . should_equal 42 + (single_key_dict (Child.Value 1) . at (Child.Value 1.0)) . should_equal 42 + + + group_builder.specify "should support another Dictionary with NaN keys as key" <| + Dictionary.singleton (Dictionary.singleton Number.nan 1) 42 . size . should_equal 1 + Dictionary.singleton (Dictionary.singleton Number.nan 1) 42 . keys . at 0 . keys . to_text . should_equal "[NaN]" + Dictionary.singleton (Dictionary.singleton Number.nan 1) 42 . keys . at 0 . get Number.nan . should_equal 1 + Dictionary.singleton (Dictionary.singleton Number.nan 1) 42 . at (Dictionary.singleton Number.nan 1) . should_equal 42 + + group_builder.specify "should support atoms with custom comparators that violate reflexivity as keys" <| + k = My_Nan.Value "foo" + k2 = My_Nan.Value "foo" + (k==k).should_be_true + (k==k2).should_be_false + Meta.is_same_object k k2 . should_be_false + Meta.is_same_object k k . should_be_true + m = Dictionary.singleton k 10 + m.contains_key k . should_be_true + m.get k . should_equal 10 + m.contains_key k2 . should_be_false + + m2 = m.insert k2 20 + m2.get k . should_equal 10 + m2.get k2 . should_equal 20 + m2.size . should_equal 2 + + m3 = m2.insert k 30 + m3.size . should_equal 2 + m3.get k . should_equal 30 + + group_builder.specify "should support atom with custom comparators with complicated hash method" <| + keys = 0.up_to 500 . map ix-> + value = ["A", "B", "C", "D", "E"].at (ix % 5) + hash_code = Comparable.from value . hash value + My_Key.Value hash_code value ix + distinct_keys = keys.fold Dictionary.empty acc_dict-> + item-> + acc_dict.insert item True + distinct_keys.size . should_equal 5 + distinct_key_values = keys.map (_.value) . fold Dictionary.empty acc_dict-> + item-> + acc_dict.insert item True + distinct_key_values.size . should_equal 5 + + group_builder.specify "should not drop warnings from keys" <| + key = Warning.attach "my_warn" "my_key" + dict = Dictionary.singleton key 42 + (Warning.get_all (dict.keys.at 0)).length . should_equal 1 + + group_builder.specify "should not drop warnings from values" <| + val = Warning.attach "my_warn" "my_val" + dict = Dictionary.singleton 42 val + (Warning.get_all (dict.values.at 0)).length . should_equal 1 + + group_builder.specify "should convert the whole Dictionary to a vector" <| + m = Dictionary.empty . insert 0 0 . insert 3 -5 . insert 1 2 + m.to_vector.sort on=_.first . should_equal [[0, 0], [1, 2], [3, -5]] + + group_builder.specify "should allow building the Dictionary from two vectors" <| + expected = Dictionary.empty . insert 0 0 . insert 3 -5 . insert 1 2 + Dictionary.from_keys_and_values [0, 3, 1] [0, -5, 2] . should_equal expected + + group_builder.specify "should allow building the Dictionary from vector like things" <| + expected = Dictionary.empty . insert 0 0 . insert 1 -5 . insert 2 2 + Dictionary.from_keys_and_values (0.up_to 3) [0, -5, 2] . should_equal expected + + group_builder.specify "should not allow building with duplicate keys unless explicitly allowed" <| + expected = Dictionary.empty . insert 0 0 . insert 3 -5 . insert 1 2 + Dictionary.from_keys_and_values [0, 3, 1, 0] [3, -5, 2, 0] . should_fail_with Illegal_Argument + Dictionary.from_keys_and_values [0, 3, 1, 0] [3, -5, 2, 0] error_on_duplicates=False . should_equal expected + + group_builder.specify "should not allow different length vectors when building" <| + Dictionary.from_keys_and_values [0, 3, 1] [3, -5, 2, 0] . should_fail_with Illegal_Argument + + group_builder.specify "should allow building the Dictionary from a vector" <| + expected = Dictionary.empty . insert 0 0 . insert 3 -5 . insert 1 2 + vec = [[0, 0], [3, -5], [1, 2]] + Dictionary.from_vector vec . should_equal expected + + group_builder.specify "should fail when building the Dictionary from wrong vector" <| + Dictionary.from_vector [["A", 1, "B", 2]] . should_fail_with Illegal_Argument + + group_builder.specify "should not allow duplicates when building the Dictionary from a vector, unless explicitly allowed" <| + vec = [[0, 0], [3, -5], [1, 2], [0, 1]] + d1 = Dictionary.from_vector vec + d1.should_fail_with Illegal_Argument + d1.catch.message . should_equal "`Dictionary.from_vector` encountered duplicate key: 0" + + d2 = Dictionary.from_vector vec error_on_duplicates=False + Problems.assume_no_problems d2 + d2.get 0 . should_equal 1 + d2.get 3 . should_equal -5 + + group_builder.specify "should disallow duplicate keys when transforming the Dictionary" <| + d = Dictionary.from_vector [[1, 2], [11, 3]] + d2 = d.transform (k -> v -> [k % 10, v*2]) + d2.should_fail_with Illegal_Argument + d2.catch.message . should_equal "`Dictionary.transform` encountered duplicate key: 1" + + group_builder.specify "should allow mapping over values" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + expected = Dictionary.empty . insert 1 4 . insert 2 8 + d.map (v -> v*2) . should_equal expected + + group_builder.specify "should allow mapping over keys" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + expected = Dictionary.empty . insert 2 2 . insert 4 4 + d.map_keys (k -> k*2) . should_equal expected + + group_builder.specify "should allow mapping with keys" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + expected = Dictionary.empty . insert 1 3 . insert 2 6 + d.map_with_key (k -> v -> k + v) . should_equal expected + + group_builder.specify "should allow iterating over each value" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + expected_vec = [2, 4] + vec = Vector.build builder-> + d.each (v -> builder.append v) + vec . should_equal expected_vec + + group_builder.specify "should allow iterating over each key-value pair" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + expected_vec = [3, 6] + vec = Vector.build builder-> + d.each_with_key (k -> v -> builder.append (k+v)) + vec . should_equal expected_vec + + group_builder.specify "should allow folding over the values" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + d.fold 0 (+) . should_equal 6 + + group_builder.specify "should allow folding over the key-value pairs" <| + d = Dictionary.empty . insert 1 2 . insert 2 4 + d.fold_with_key 0 (l -> k -> v -> l + k + v) . should_equal 9 + + group_builder.specify "should be able to add a Nothing key to a Dictionary of Text" <| + m = Dictionary.empty . insert "A" 2 . insert Nothing 1 . insert "B" 3 + m.at "A" . should_equal 2 + m.at "B" . should_equal 3 + m.at Nothing . should_equal 1 + + group_builder.specify "should be able to add a Nothing key to a Dictionary of Integer" <| + m = Dictionary.empty . insert 100 2 . insert Nothing 1 . insert 200 3 + m.at 100 . should_equal 2 + m.at 200 . should_equal 3 + m.at Nothing . should_equal 1 + + suite_builder.group "Polyglot keys and values" group_builder-> + group_builder.specify "should support polyglot keys" <| + dict = Dictionary.singleton (js_str "A") 42 + dict.size.should_equal 1 + dict.get "A" . should_equal 42 + dict.get (js_str "A") . should_equal 42 + + group_builder.specify "should support host objects as keys" <| + # java.nio.path.Path has proper implementation of hashCode + dict = Dictionary.singleton (File_Utils.toPath "/home/user/file.txt") 42 + dict.get "X" . should_equal Nothing + dict.get "A" . should_equal Nothing + dict.get (File_Utils.toPath "/home/user/file.txt") . should_equal 42 + + group_builder.specify "should support Python objects as keys" pending=pending_python_missing <| + py_obj = py_wrapper 42 + dict = Dictionary.singleton py_obj "Value" + dict.get py_obj . should_equal "Value" + + group_builder.specify "should support Python objects as values" pending=pending_python_missing <| + dict = Dictionary.singleton "A" (py_wrapper 42) + dict.get "A" . data . should_equal 42 + + group_builder.specify "should insert entries to a polyglot map" pending=pending_python_missing <| + dict = py_dict_from_vec ["A", 1, "B", 2] + dict.insert "C" 3 . keys . sort . should_equal ["A", "B", "C"] + + group_builder.specify "should remove entries from a polyglot map" pending=pending_python_missing <| + dict = py_dict_from_vec ["A", 1, "B", 2] + dict.remove "B" . to_vector . should_equal [["A", 1]] + + suite_builder.group "non-linear inserts" group_builder-> + group_builder.specify "should handle inserts with different keys" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d1.insert "C" 3 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["C", 3]] + + group_builder.specify "should handle inserts with same keys (1)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "A" 2 + d3 = d1.insert "A" 3 + d4 = d1.insert "B" 4 + d2.to_vector.sort on=_.first . should_equal [["A", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 4]] + + group_builder.specify "should handle inserts with same keys (2)" <| + d1 = Dictionary.singleton "foo" 1 + d2 = d1.insert "baz" 2 + d3 = d2.insert "foo" 3 + d1.to_vector.sort on=_.first . should_equal [['foo', 1]] + d2.to_vector.sort on=_.first . should_equal [['baz', 2], ['foo', 1]] + d3.to_vector.sort on=_.first . should_equal [['baz', 2], ['foo', 3]] + + group_builder.specify "should handle inserts with same keys (3)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "A" 3 + d4 = d2.insert "C" 4 + d1.to_vector.sort on=_.first . should_equal [["A", 1]] + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 4]] + + group_builder.specify "should handle inserts with same keys (4)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "C" 3 + d4 = d2.insert "D" 4 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["D", 4]] + + group_builder.specify "should handle inserts with same keys (5)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "A" 3 + d4 = d2.insert "A" 4 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] + d4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2]] + + group_builder.specify "should handle inserts with same keys (6)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "C" 3 + d4 = d2.insert "A" 4 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2]] + + group_builder.specify "should handle inserts with same keys (7)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "C" 3 + d4 = d3.insert "D" 4 + d5 = d2.insert "A" 5 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3], ["D", 4]] + d5.to_vector.sort on=_.first . should_equal [["A", 5], ["B", 2]] + + group_builder.specify "should handle inserts with same keys (8)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "C" 3 + d4 = d3.insert "A" 4 + d5 = d2.insert "A" 5 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2], ["C", 3]] + d5.to_vector.sort on=_.first . should_equal [["A", 5], ["B", 2]] + + group_builder.specify "should handle inserts with same keys (9)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "A" 3 + d4 = d2.insert "B" 4 + d5 = d2.insert "C" 5 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 4]] + d5.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 5]] + + group_builder.specify "should handle inserts with same keys (10)" <| + d1 = Dictionary.singleton "A" 1 + d2 = d1.insert "B" 2 + d3 = d2.insert "C" 3 + d4 = d2.insert "D" 4 + d5 = d2.insert "E" 5 + d2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] + d3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + d4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["D", 4]] + d5.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["E", 5]] + + suite_builder.group "Polyglot hash maps" group_builder-> + group_builder.specify "should pass Dictionaries as immutable maps to other languages" pending=pending_python_missing <| + dict = Dictionary.singleton "A" 1 + # Python's KeyError should be raised + Test.expect_panic_with (py_update_dict dict "A" 2) Any + dict.get "A" . should_equal 1 + + group_builder.specify "should treat JavaScript maps as Enso Dictionaries" <| + js_dict = js_dict_from_vec ["A", 1, "B", 2] + dict = js_dict.insert "C" 3 + js_dict.to_vector.should_equal [["A", 1], ["B", 2]] + dict.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] + + group_builder.specify "should treat Java Map as Enso Dictionary" <| + sort_by_keys vec = vec.sort by=x-> y-> Ordering.compare x.first y.first + dict = JavaMap.of "A" 1 "B" 2 + (sort_by_keys dict.to_vector) . should_equal [["A", 1], ["B", 2]] + (sort_by_keys (dict.insert "C" 3 . to_vector)) . should_equal [["A", 1], ["B", 2], ["C", 3]] + + group_builder.specify "should treat Python dicts as Enso Dictionaries" pending=pending_python_missing <| + py_dict = py_dict_from_vec ["A", 1, "B", 2] + dict = py_dict.insert "C" 3 + py_dict.not_empty . should_be_true + py_dict.to_vector . should_contain_the_same_elements_as [["A", 1], ["B", 2]] + dict.to_vector . should_contain_the_same_elements_as [["A", 1], ["B", 2], ["C", 3]] + py_empty_dict.is_empty.should_be_true + py_empty_dict.insert "A" 1 . insert "A" 2 . get "A" . should_equal 2 + + group_builder.specify "should be able to remove entries" pending=pending_python_missing <| + py_dict_from_vec ["A", 1, "B", 2] . remove "A" . size . should_equal 1 + py_dict_from_vec ["A", 1, "B", 2] . remove "A" . get "B" . should_equal 2 + + group_builder.specify "should be able to remove NaN keys" pending=pending_python_missing <| + py_dict_from_vec [Number.nan, 1] . remove Number.nan . size . should_equal 0 + + group_builder.specify "should pass Dictionaries with null keys to Python and back" pending=pending_python_missing <| + # Python supports None as keys, Enso support Nothing as keys + py_dict = py_dict_from_map (Dictionary.singleton Nothing 42) + py_dict.get Nothing . should_equal 42 + py_dict.insert "A" 23 . get Nothing . should_equal 42 + py_dict.insert Nothing 23 . get Nothing . should_equal 23 + + group_builder.specify "should treat Enso Dictionaries as Python dicts when passed to Python" pending=pending_python_missing <| + dict1 = Dictionary.singleton "A" 1 . insert "B" 2 + py_vec_from_map dict1 . should_contain_the_same_elements_as [["A", 1], ["B", 2]] + dict2 = Dictionary.singleton "A" 1 . insert Nothing 2 + py_vec_from_map dict2 . should_contain_the_same_elements_as [["A", 1], [Nothing, 2]] + + +add_common_specs suite_builder prefix:Text (pending : (Text | Nothing)) (empty_dict_fn : (Nothing -> Dictionary)) = + # Not on a single line - empty_dict is a method, not a variable + empty_dict = + empty_dict_fn Nothing + + suite_builder.group prefix+": Common polyglot Dictionary operations" pending=pending group_builder-> + group_builder.specify "should get the default comparator for polyglot maps" <| + Comparable.from empty_dict . should_equal Default_Comparator + + group_builder.specify "should compare two hash maps" <| + (empty_dict.insert "a" 1).should_equal (empty_dict.insert "a" 1) + (empty_dict.insert "b" 2).should_not_equal (empty_dict.insert "a" 1) + empty_dict.should_equal empty_dict + empty_dict.should_not_equal (empty_dict.insert "a" 1) + (empty_dict.insert "a" 1 . insert "b" 2).should_equal (empty_dict.insert "b" 2 . insert "a" 1) + + group_builder.specify "should allow checking for non emptiness" <| + non_empty = empty_dict . insert "foo" 1234 + empty_dict.not_empty . should_be_false + non_empty.not_empty . should_be_true + + group_builder.specify "should allow checking its size" <| + non_empty = empty_dict.insert "a" "b" . insert "x" "y" + empty_dict.size . should_equal 0 + non_empty.size . should_equal 2 + + group_builder.specify "should allow checking for emptiness" <| + non_empty = empty_dict . insert "foo" 1234 + empty_dict.is_empty . should_be_true + non_empty.is_empty . should_be_false + + group_builder.specify "should handle incomparable values as keys" <| + empty_dict.insert Number.nan 1 . insert Number.nan 2 . get Number.nan . should_equal 2 + + group_builder.specify "should handle Nothing as values" <| + empty_dict.insert 1 Nothing . at 1 . should_equal Nothing + empty_dict.insert Nothing Nothing . at Nothing . should_equal Nothing + + group_builder.specify "should support rewriting values with same keys" <| + dict = Dictionary.singleton "a" 1 . insert "a" 42 + dict.size.should_equal 1 + dict.get "a" . should_equal 42 + + group_builder.specify "should allow storing atoms as values" <| + json = Json.parse '{"a": 1}' + pair = Pair.new "first" "second" + dict = Dictionary.singleton 0 json . insert 1 pair + dict.get 0 . should_equal json + dict.get 1 . should_equal pair + + group_builder.specify "should support NaN as keys" <| + empty_dict.insert Number.nan 1 . contains_key Number.nan . should_be_true + empty_dict.insert Number.nan 1 . values . should_equal [1] + empty_dict.insert Number.nan 1 . insert Number.nan 2 . contains_key Number.nan . should_be_true + empty_dict.insert Number.nan 1 . insert Number.nan 2 . values . should_equal [2] + empty_dict.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . contains_key Number.nan . should_be_true + empty_dict.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . contains_key "key" . should_be_true + empty_dict.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . at Number.nan . should_equal 3 + empty_dict.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . at "key" . should_equal 2 + empty_dict.insert Number.nan 1 . insert Number.nan Number.nan . at Number.nan . to_text . should_equal "NaN" + empty_dict.insert Number.nan 1 . insert Number.nan Number.nan . remove Number.nan . size . should_equal 0 + + group_builder.specify "should support arbitrary atoms as keys" <| + dict = empty_dict . insert (Pair.new "one" "two") 42 + (dict.get (Pair.new "one" "two")).should_equal 42 + (dict.get (Pair.new "A" "B")).should_equal Nothing + (dict.get (Pair.new "two" "two")).should_equal Nothing + + group_builder.specify "should support vectors as keys" <| + dict = empty_dict . insert [1, "a", 2] "Value" + dict.size.should_equal 1 + dict.get [1, "a", 2] . should_equal "Value" + + group_builder.specify "should support dates as keys" <| + dict = empty_dict.insert (Date.new 1993) 1 . insert (Date.new 1993 2 5) 2 . insert (Date_Time.new 1993 2 5 13 45) 3 + dict.size.should_equal 3 + dict.get (Date.new 1993 6 7) . should_equal Nothing + dict.get (Date.new 1993) . should_equal 1 + dict.get (Date_Time.new 1993) . should_equal Nothing + dict.get (Date.new 1993 2 5) . should_equal 2 + dict.get (Date_Time.new 1993 2 5) . should_equal Nothing + dict.get (Date_Time.new 1993 2 5 13 45) . should_equal 3 + + group_builder.specify "should support another hash map as key" <| + keys = empty_dict.insert (Pair.new "one" "two") 42 + dict = empty_dict.insert keys 23 + dict.size.should_equal 1 + (dict.get "A").should_equal Nothing + (dict.get keys).should_equal 23 + (dict.get dict).should_equal Nothing + + group_builder.specify "should handle keys with standard equality semantics" <| + dict = empty_dict.insert 2 "Hello" + (dict.get 2).should_equal "Hello" + (dict.get 2.0).should_equal "Hello" + (empty_dict.insert 2 "Hello").should_equal (empty_dict.insert 2.0 "Hello") + + group_builder.specify "should handle Nothing as keys" <| + empty_dict.insert Nothing 3 . get Nothing . should_equal 3 + empty_dict.insert Nothing 1 . insert Nothing 2 . get Nothing . should_equal 2 + empty_dict.insert Nothing 1 . should_equal (empty_dict.insert Nothing 1) + empty_dict.insert Nothing 1 . insert Nothing 2 . at Nothing . should_equal 2 + + group_builder.specify "should handle JavaScript null as keys" <| + empty_dict.insert js_null 1 . at Nothing . should_equal 1 + + group_builder.specify "should handle Python None as keys" pending=pending_python_missing <| + empty_dict.insert py_none 1 . at Nothing . should_equal 1 + + group_builder.specify "should define a well-defined text conversion" <| + d = empty_dict . insert 0 0 . insert 3 -5 . insert 1 2 + d.to_text . should_contain "0=0" + d.to_text . should_contain "3=-5" + d.to_text . should_contain "1=2" + + group_builder.specify "should define structural equality" <| + dict_1 = empty_dict . insert "1" 2 . insert "2" "1" + dict_2 = empty_dict . insert "1" 2 . insert "2" "1" + dict_3 = empty_dict + dict_1==dict_2 . should_be_true + dict_1==dict_3 . should_be_false + dict_2==dict_3 . should_be_false + + group_builder.specify "should allow inserting and looking up values" <| + m = empty_dict . insert "foo" 134 . insert "bar" 654 . insert "baz" "spam" + m.at "foo" . should_equal 134 + m.at "bar" . should_equal 654 + m.at "baz" . should_equal "spam" + (m.at "nope").should_fail_with No_Such_Key + + group_builder.specify "should support get" <| + m = empty_dict . insert 2 3 + m.get 2 0 . should_equal 3 + m.get 1 10 . should_equal 10 + m.get 2 (Panic.throw "missing") . should_equal 3 + + group_builder.specify "should allow getting a vector of the keys" <| + m = empty_dict . insert 1 2 . insert 2 4 + m.keys . should_equal [1, 2] + + group_builder.specify "should allow getting a vector of the values" <| + m = empty_dict . insert 1 2 . insert 2 4 + m.values . should_equal [2, 4] + + group_builder.specify "should support contains_key" <| + m = empty_dict . insert 2 3 + m.contains_key 2 . should_be_true + m.contains_key 1 . should_be_false + + group_builder.specify "should allow transforming the dictionary" <| + m = empty_dict . insert 1 2 . insert 2 4 + expected = empty_dict . insert "1" 4 . insert "2" 8 + m.transform (k -> v -> [k.to_text, v*2]) . should_equal expected + + group_builder.specify "should be able to remove entries (1)" <| + m1 = empty_dict.insert "A" 1 . insert "B" 2 + m2 = m1.remove "B" + m2.get "A" . should_equal 1 + m2.remove "A" . should_equal empty_dict + m1.remove "foo" . should_fail_with No_Such_Key + + group_builder.specify "should be able to remove entries (2)" <| + m1 = empty_dict.insert "A" 1 + m2 = m1.insert "B" 2 + m3 = m1.insert "C" 3 + m2.remove "A" . to_vector . should_equal [["B", 2]] + m2.remove "B" . to_vector . should_equal [["A", 1]] + m3.remove "A" . to_vector . should_equal [["C", 3]] + m3.remove "C" . to_vector . should_equal [["A", 1]] + + group_builder.specify "should be able to remove entries (3)" <| + m = empty_dict.insert "A" 1 . insert "B" 2 . insert "C" 3 + m.remove "B" . should_equal (empty_dict.insert "A" 1 . insert "C" 3) + +main filter=Nothing = + suite = Test.build suite_builder-> + add_specs suite_builder + suite.run_with_filter filter diff --git a/test/Base_Tests/src/Data/Set_Spec.enso b/test/Base_Tests/src/Data/Hashset_Spec.enso similarity index 55% rename from test/Base_Tests/src/Data/Set_Spec.enso rename to test/Base_Tests/src/Data/Hashset_Spec.enso index 28de9a0d8d5..d333bc6fcd0 100644 --- a/test/Base_Tests/src/Data/Set_Spec.enso +++ b/test/Base_Tests/src/Data/Hashset_Spec.enso @@ -5,10 +5,11 @@ from Standard.Test import all add_specs suite_builder = - suite_builder.group "Enso Set" group_builder-> + suite_builder.group "Enso Hashset" group_builder-> group_builder.specify "should allow checking for emptiness" <| - empty_map = Set.empty - non_empty = Set.empty . insert "foo" + empty_map = + Hashset.empty + non_empty = Hashset.empty . insert "foo" empty_map.is_empty . should_be_true non_empty.is_empty . should_be_false @@ -16,34 +17,34 @@ add_specs suite_builder = non_empty.not_empty . should_be_true group_builder.specify "should be constructed from a vector" <| - s1 = Set.from_vector [1, 2, 3, 2] + s1 = Hashset.from_vector [1, 2, 3, 2] s1.size . should_equal 3 s1.to_vector.sort . should_equal [1, 2, 3] - r2 = Set.from_vector [1, 2, 2] error_on_duplicates=True + r2 = Hashset.from_vector [1, 2, 2] error_on_duplicates=True r2.should_fail_with Illegal_Argument group_builder.specify "should allow checking contains" <| - s1 = Set.from_vector [1, 2, 3, 2] + s1 = Hashset.from_vector [1, 2, 3, 2] s1.contains 1 . should_be_true s1.contains 2 . should_be_true s1.contains 3 . should_be_true s1.contains 4 . should_be_false group_builder.specify "should allow checking contains with relational NULL logic" <| - Set.from_vector [1, 2] . contains_relational 1 . should_be_true - Set.from_vector [1, 2] . contains_relational 3 . should_be_false - Set.from_vector [1, 2, Nothing] . contains_relational 1 . should_be_true - Set.from_vector [1, 2, Nothing] . contains_relational 3 . should_equal Nothing - Set.from_vector [1, 2, Nothing] . contains_relational Nothing . should_equal Nothing - Set.from_vector [1, 2] . contains_relational Nothing . should_equal Nothing - Set.from_vector [Nothing] . contains_relational Nothing . should_equal Nothing - Set.from_vector [] . contains_relational Nothing . should_be_false + Hashset.from_vector [1, 2] . contains_relational 1 . should_be_true + Hashset.from_vector [1, 2] . contains_relational 3 . should_be_false + Hashset.from_vector [1, 2, Nothing] . contains_relational 1 . should_be_true + Hashset.from_vector [1, 2, Nothing] . contains_relational 3 . should_equal Nothing + Hashset.from_vector [1, 2, Nothing] . contains_relational Nothing . should_equal Nothing + Hashset.from_vector [1, 2] . contains_relational Nothing . should_equal Nothing + Hashset.from_vector [Nothing] . contains_relational Nothing . should_equal Nothing + Hashset.from_vector [] . contains_relational Nothing . should_be_false group_builder.specify "should allow to compute a union, intersection and difference" <| - s1 = Set.from_vector [1, 2] - s2 = Set.from_vector [2, 3] - s3 = Set.from_vector [3, 4] + s1 = Hashset.from_vector [1, 2] + s2 = Hashset.from_vector [2, 3] + s3 = Hashset.from_vector [3, 4] (s1.union s2).to_vector.sort . should_equal [1, 2, 3] (s1.union s3).to_vector.sort . should_equal [1, 2, 3, 4] @@ -54,19 +55,19 @@ add_specs suite_builder = (s1.difference s1).to_vector . should_equal [] group_builder.specify "should allow to check for equality of two sets" <| - s1 = Set.from_vector [1, 2] - s2 = Set.from_vector [2, 1, 1] - s3 = Set.from_vector [1, 2, 3] + s1 = Hashset.from_vector [1, 2] + s2 = Hashset.from_vector [2, 1, 1] + s3 = Hashset.from_vector [1, 2, 3] (s1 == s2) . should_be_true (s1 == s1) . should_be_true (s1 == s3) . should_be_false group_builder.specify "should be able to convert to text" <| - s1 = Set.from_vector ["1", "2", "3"] - s2 = Set.from_vector [1, 2, 3] - s1.to_text.should_equal "Set{'1', '2', '3'}" - s2.to_text.should_equal "Set{1, 2, 3}" + s1 = Hashset.from_vector ["1", "2", "3"] + s2 = Hashset.from_vector [1, 2, 3] + s1.to_text.should_equal "Hashset{'1', '2', '3'}" + s2.to_text.should_equal "Hashset{1, 2, 3}" main filter=Nothing = suite = Test.build suite_builder-> diff --git a/test/Base_Tests/src/Data/Json_Spec.enso b/test/Base_Tests/src/Data/Json_Spec.enso index 799d50625a5..2dfd4b1c2b6 100644 --- a/test/Base_Tests/src/Data/Json_Spec.enso +++ b/test/Base_Tests/src/Data/Json_Spec.enso @@ -85,13 +85,13 @@ add_specs suite_builder = Json.parse '{"constructor": "Skew", "population": true}' . into Statistic . should_equal (Statistic.Skew True) Json.parse '{"constructor": "NotARealOne", "population": true}' . into Statistic . should_fail_with Illegal_Argument - group_builder.specify "should be able to convert a JS_Object into a Map using into" <| - Json.parse '{"a": 15, "b": 20, "c": "X", "d": null}' . into Map . should_equal (Map.from_vector [["a", 15], ["b", 20], ["c", "X"], ["d", Nothing]]) - Json.parse '{}' . into Map . should_equal Map.empty + group_builder.specify "should be able to convert a JS_Object into a Dictionary using into" <| + Json.parse '{"a": 15, "b": 20, "c": "X", "d": null}' . into Dictionary . should_equal (Dictionary.from_vector [["a", 15], ["b", 20], ["c", "X"], ["d", Nothing]]) + Json.parse '{}' . into Dictionary . should_equal Dictionary.empty # [] parses as a vector/array which does not have the `into` method, that only works for {} objects: Test.expect_panic No_Such_Method <| - Json.parse '[]' . into Map + Json.parse '[]' . into Dictionary group_builder.specify "should be able to deserialize Date" <| '{"type": "Date", "constructor": "new", "year": 2018, "month": 7, "day": 3}'.should_parse_as (Date.new 2018 7 3) diff --git a/test/Base_Tests/src/Data/Map_Spec.enso b/test/Base_Tests/src/Data/Map_Spec.enso deleted file mode 100644 index 975b8f7f88a..00000000000 --- a/test/Base_Tests/src/Data/Map_Spec.enso +++ /dev/null @@ -1,637 +0,0 @@ -from Standard.Base import all -import Standard.Base.Errors.Illegal_Argument.Illegal_Argument -import Standard.Base.Errors.No_Such_Key.No_Such_Key - -from Standard.Test import all - - -polyglot java import java.util.Map as JavaMap -polyglot java import org.enso.base.file_system.File_Utils - -## Type that violates reflexivity -type My_Nan - Value comment:Text - -type My_Nan_Comparator - compare _ _ = Nothing - hash _ = 0 - -Comparable.from (_:My_Nan) = My_Nan_Comparator - -type My_Key - Value hash_code:Integer value:Text idx:Integer - -type My_Key_Comparator - # Comparison ignores idx field - compare x y = - if x.hash_code != y.hash_code then Nothing else - if x.value == y.value then Ordering.Equal else Nothing - - hash x = x.hash_code - -Comparable.from (_:My_Key) = My_Key_Comparator - - -foreign js js_str str = """ - return new String(str) - -foreign js js_null = """ - return null - -foreign js js_empty_dict = """ - return new Map() - -foreign python py_empty_dict = """ - return {} - -foreign js js_dict_from_vec vec = """ - dict = new Map() - for (let i = 0; i < vec.length; i += 2) { - dict.set(vec[i], vec[i+1]) - } - return dict - -foreign python py_none = """ - return None - -foreign python py_dict_from_vec vec = """ - d = {} - for i in range(0, len(vec), 2): - d[vec[i]] = vec[i + 1] - return d - -foreign python py_dict_from_map map = """ - d = dict() - for key in map.__iter__(): - d[key] = map[key] - return d - -foreign python py_vec_from_map map = """ - vec = [] - for key in map.__iter__(): - value = map[key] - vec.append([key, value]) - return vec - -# Should throw error - updating immutable map from Enso -foreign python py_update_dict map key val = """ - map[key] = val - -foreign python py_wrapper obj = """ - class MyClass: - def __init__(self, obj): - self.data = obj - return MyClass(obj) - -pending_python_missing = if Polyglot.is_language_installed "python" then Nothing else "Can't run Python tests, Python is not installed." - -type Child - Value data - -type Parent - Value child - -type GrandParent - Value parent - -add_specs suite_builder = - languages = Vector.build builder-> - builder . append ["Enso", _-> Map.empty, Nothing] - builder . append ["Java", _-> JavaMap.of, Nothing] - builder . append ["JavaScript", _-> js_empty_dict, Nothing] - builder . append ["Python", _-> py_empty_dict, pending_python_missing] - languages.each entry-> - lang = entry.get 0 - empty_map_fn = entry.get 1 - pending = entry.get 2 - add_common_specs suite_builder lang pending empty_map_fn - - suite_builder.group "Enso maps" group_builder-> - - - group_builder.specify "should use proper hash code for keys" <| - single_key_map key = Map.singleton key 42 - grand_parent_1 = GrandParent.Value (Parent.Value (Child.Value 2)) - grand_parent_2 = GrandParent.Value (Parent.Value (Child.Value 2.0)) - - (single_key_map 2 . at 2.0) . should_equal 42 - (single_key_map -2 . at -2.0) . should_equal 42 - (single_key_map 'ś' . at 's\u0301') . should_equal 42 - (single_key_map 's\u0301' . at 'ś') . should_equal 42 - (single_key_map 'éabc' . at 'e\u0301abc') . should_equal 42 - (single_key_map 'e\u0301abc' . at 'éabc') . should_equal 42 - (single_key_map grand_parent_1 . at grand_parent_2) . should_equal 42 - (single_key_map (Json.parse '{"a": 1}') . at (Json.parse '{"a": 1}')) . should_equal 42 - (single_key_map (Child.Value 1) . at (Child.Value 1.0)) . should_equal 42 - - - group_builder.specify "should support another hash map with NaN keys as key" <| - Map.singleton (Map.singleton Number.nan 1) 42 . size . should_equal 1 - Map.singleton (Map.singleton Number.nan 1) 42 . keys . at 0 . keys . to_text . should_equal "[NaN]" - Map.singleton (Map.singleton Number.nan 1) 42 . keys . at 0 . get Number.nan . should_equal 1 - Map.singleton (Map.singleton Number.nan 1) 42 . at (Map.singleton Number.nan 1) . should_equal 42 - - group_builder.specify "should support atoms with custom comparators that violate reflexivity as keys" <| - k = My_Nan.Value "foo" - k2 = My_Nan.Value "foo" - (k==k).should_be_true - (k==k2).should_be_false - Meta.is_same_object k k2 . should_be_false - Meta.is_same_object k k . should_be_true - m = Map.empty.insert k 10 - m.contains_key k . should_be_true - m.get k . should_equal 10 - m.contains_key k2 . should_be_false - - m2 = m.insert k2 20 - m2.get k . should_equal 10 - m2.get k2 . should_equal 20 - m2.size . should_equal 2 - - m3 = m2.insert k 30 - m3.size . should_equal 2 - m3.get k . should_equal 30 - - group_builder.specify "should support atom with custom comparators with complicated hash method" <| - keys = 0.up_to 500 . map ix-> - value = ["A", "B", "C", "D", "E"].at (ix % 5) - hash_code = Comparable.from value . hash value - My_Key.Value hash_code value ix - distinct_keys = keys.fold Map.empty acc_map-> - item-> - acc_map.insert item True - distinct_keys.size . should_equal 5 - distinct_key_values = keys.map (_.value) . fold Map.empty acc_map-> - item-> - acc_map.insert item True - distinct_key_values.size . should_equal 5 - - group_builder.specify "should not drop warnings from keys" <| - key = Warning.attach "my_warn" "my_key" - map = Map.singleton key 42 - (Warning.get_all (map.keys.at 0)).length . should_equal 1 - - group_builder.specify "should not drop warnings from values" <| - val = Warning.attach "my_warn" "my_val" - map = Map.singleton 42 val - (Warning.get_all (map.values.at 0)).length . should_equal 1 - - group_builder.specify "should convert the whole map to a vector" <| - m = Map.empty . insert 0 0 . insert 3 -5 . insert 1 2 - m.to_vector.sort on=_.first . should_equal [[0, 0], [1, 2], [3, -5]] - - group_builder.specify "should allow building the map from two vectors" <| - expected = Map.empty . insert 0 0 . insert 3 -5 . insert 1 2 - Map.from_keys_and_values [0, 3, 1] [0, -5, 2] . should_equal expected - - group_builder.specify "should allow building the map from vector like things" <| - expected = Map.empty . insert 0 0 . insert 1 -5 . insert 2 2 - Map.from_keys_and_values (0.up_to 3) [0, -5, 2] . should_equal expected - - group_builder.specify "should not allow building with duplicate keys unless explicitly allowed" <| - expected = Map.empty . insert 0 0 . insert 3 -5 . insert 1 2 - Map.from_keys_and_values [0, 3, 1, 0] [3, -5, 2, 0] . should_fail_with Illegal_Argument - Map.from_keys_and_values [0, 3, 1, 0] [3, -5, 2, 0] error_on_duplicates=False . should_equal expected - - group_builder.specify "should not allow different length vectors when building" <| - Map.from_keys_and_values [0, 3, 1] [3, -5, 2, 0] . should_fail_with Illegal_Argument - - group_builder.specify "should allow building the map from a vector" <| - expected = Map.empty . insert 0 0 . insert 3 -5 . insert 1 2 - vec = [[0, 0], [3, -5], [1, 2]] - Map.from_vector vec . should_equal expected - - group_builder.specify "should fail when building the map from wrong vector" <| - Map.from_vector [["A", 1, "B", 2]] . should_fail_with Illegal_Argument - - group_builder.specify "should not allow duplicates when building the map from a vector, unless explicitly allowed" <| - vec = [[0, 0], [3, -5], [1, 2], [0, 1]] - m1 = Map.from_vector vec - m1.should_fail_with Illegal_Argument - m1.catch.message . should_equal "`Map.from_vector` encountered duplicate key: 0" - - m2 = Map.from_vector vec error_on_duplicates=False - Problems.assume_no_problems m2 - m2.get 0 . should_equal 1 - m2.get 3 . should_equal -5 - - group_builder.specify "should disallow duplicate keys when transforming the map" <| - m = Map.from_vector [[1, 2], [11, 3]] - m2 = m.transform (k -> v -> [k % 10, v*2]) - m2.should_fail_with Illegal_Argument - m2.catch.message . should_equal "`Map.transform` encountered duplicate key: 1" - - group_builder.specify "should allow mapping over values" <| - m = Map.empty . insert 1 2 . insert 2 4 - expected = Map.empty . insert 1 4 . insert 2 8 - m.map (v -> v*2) . should_equal expected - - group_builder.specify "should allow mapping over keys" <| - m = Map.empty . insert 1 2 . insert 2 4 - expected = Map.empty . insert 2 2 . insert 4 4 - m.map_keys (k -> k*2) . should_equal expected - - group_builder.specify "should allow mapping with keys" <| - m = Map.empty . insert 1 2 . insert 2 4 - expected = Map.empty . insert 1 3 . insert 2 6 - m.map_with_key (k -> v -> k + v) . should_equal expected - - group_builder.specify "should allow iterating over each value" <| - m = Map.empty . insert 1 2 . insert 2 4 - expected_vec = [2, 4] - vec = Vector.build builder-> - m.each (v -> builder.append v) - vec . should_equal expected_vec - - group_builder.specify "should allow iterating over each key-value pair" <| - m = Map.empty . insert 1 2 . insert 2 4 - expected_vec = [3, 6] - vec = Vector.build builder-> - m.each_with_key (k -> v -> builder.append (k+v)) - vec . should_equal expected_vec - - group_builder.specify "should allow folding over the values" <| - m = Map.empty . insert 1 2 . insert 2 4 - m.fold 0 (+) . should_equal 6 - - group_builder.specify "should allow folding over the key-value pairs" <| - m = Map.empty . insert 1 2 . insert 2 4 - m.fold_with_key 0 (l -> k -> v -> l + k + v) . should_equal 9 - - group_builder.specify "should be able to add a Nothing key to the map of Text" <| - m = Map.empty . insert "A" 2 . insert Nothing 1 . insert "B" 3 - m.at "A" . should_equal 2 - m.at "B" . should_equal 3 - m.at Nothing . should_equal 1 - - group_builder.specify "should be able to add a Nothing key to the map of Integer" <| - m = Map.empty . insert 100 2 . insert Nothing 1 . insert 200 3 - m.at 100 . should_equal 2 - m.at 200 . should_equal 3 - m.at Nothing . should_equal 1 - - suite_builder.group "Polyglot keys and values" group_builder-> - group_builder.specify "should support polyglot keys" <| - map = Map.singleton (js_str "A") 42 - map.size.should_equal 1 - map.get "A" . should_equal 42 - map.get (js_str "A") . should_equal 42 - - group_builder.specify "should support host objects as keys" <| - # java.nio.path.Path has proper implementation of hashCode - map = Map.singleton (File_Utils.toPath "/home/user/file.txt") 42 - map.get "X" . should_equal Nothing - map.get "A" . should_equal Nothing - map.get (File_Utils.toPath "/home/user/file.txt") . should_equal 42 - - group_builder.specify "should support Python objects as keys" pending=pending_python_missing <| - py_obj = py_wrapper 42 - map = Map.singleton py_obj "Value" - map.get py_obj . should_equal "Value" - - group_builder.specify "should support Python objects as values" pending=pending_python_missing <| - map = Map.singleton "A" (py_wrapper 42) - map.get "A" . data . should_equal 42 - - group_builder.specify "should insert entries to a polyglot map" pending=pending_python_missing <| - dict = py_dict_from_vec ["A", 1, "B", 2] - dict.insert "C" 3 . keys . sort . should_equal ["A", "B", "C"] - - group_builder.specify "should remove entries from a polyglot map" pending=pending_python_missing <| - dict = py_dict_from_vec ["A", 1, "B", 2] - dict.remove "B" . to_vector . should_equal [["A", 1]] - - suite_builder.group "non-linear inserts" group_builder-> - group_builder.specify "should handle inserts with different keys" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m1.insert "C" 3 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["C", 3]] - - group_builder.specify "should handle inserts with same keys (1)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "A" 2 - m3 = m1.insert "A" 3 - m4 = m1.insert "B" 4 - m2.to_vector.sort on=_.first . should_equal [["A", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 4]] - - group_builder.specify "should handle inserts with same keys (2)" <| - m1 = Map.singleton "foo" 1 - m2 = m1.insert "baz" 2 - m3 = m2.insert "foo" 3 - m1.to_vector.sort on=_.first . should_equal [['foo', 1]] - m2.to_vector.sort on=_.first . should_equal [['baz', 2], ['foo', 1]] - m3.to_vector.sort on=_.first . should_equal [['baz', 2], ['foo', 3]] - - group_builder.specify "should handle inserts with same keys (3)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "A" 3 - m4 = m2.insert "C" 4 - m1.to_vector.sort on=_.first . should_equal [["A", 1]] - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 4]] - - group_builder.specify "should handle inserts with same keys (4)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "C" 3 - m4 = m2.insert "D" 4 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["D", 4]] - - group_builder.specify "should handle inserts with same keys (5)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "A" 3 - m4 = m2.insert "A" 4 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] - m4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2]] - - group_builder.specify "should handle inserts with same keys (6)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "C" 3 - m4 = m2.insert "A" 4 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2]] - - group_builder.specify "should handle inserts with same keys (7)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "C" 3 - m4 = m3.insert "D" 4 - m5 = m2.insert "A" 5 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3], ["D", 4]] - m5.to_vector.sort on=_.first . should_equal [["A", 5], ["B", 2]] - - group_builder.specify "should handle inserts with same keys (8)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "C" 3 - m4 = m3.insert "A" 4 - m5 = m2.insert "A" 5 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 4], ["B", 2], ["C", 3]] - m5.to_vector.sort on=_.first . should_equal [["A", 5], ["B", 2]] - - group_builder.specify "should handle inserts with same keys (9)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "A" 3 - m4 = m2.insert "B" 4 - m5 = m2.insert "C" 5 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 3], ["B", 2]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 4]] - m5.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 5]] - - group_builder.specify "should handle inserts with same keys (10)" <| - m1 = Map.singleton "A" 1 - m2 = m1.insert "B" 2 - m3 = m2.insert "C" 3 - m4 = m2.insert "D" 4 - m5 = m2.insert "E" 5 - m2.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2]] - m3.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - m4.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["D", 4]] - m5.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["E", 5]] - - suite_builder.group "Polyglot hash maps" group_builder-> - group_builder.specify "should pass maps as immutable maps to other langs" pending=pending_python_missing <| - map = Map.singleton "A" 1 - # Python's KeyError should be raised - Test.expect_panic_with (py_update_dict map "A" 2) Any - map.get "A" . should_equal 1 - - group_builder.specify "should treat JavaScript maps as Enso maps" <| - js_dict = js_dict_from_vec ["A", 1, "B", 2] - map = js_dict.insert "C" 3 - js_dict.to_vector.should_equal [["A", 1], ["B", 2]] - map.to_vector.sort on=_.first . should_equal [["A", 1], ["B", 2], ["C", 3]] - - group_builder.specify "should treat Java Map as Enso map" <| - sort_by_keys vec = vec.sort by=x-> y-> Ordering.compare x.first y.first - jmap = JavaMap.of "A" 1 "B" 2 - (sort_by_keys jmap.to_vector) . should_equal [["A", 1], ["B", 2]] - (sort_by_keys (jmap.insert "C" 3 . to_vector)) . should_equal [["A", 1], ["B", 2], ["C", 3]] - - group_builder.specify "should treat Python dicts as Enso maps" pending=pending_python_missing <| - py_dict = py_dict_from_vec ["A", 1, "B", 2] - map = py_dict.insert "C" 3 - py_dict.not_empty . should_be_true - py_dict.to_vector . should_contain_the_same_elements_as [["A", 1], ["B", 2]] - map.to_vector . should_contain_the_same_elements_as [["A", 1], ["B", 2], ["C", 3]] - py_empty_dict.is_empty.should_be_true - py_empty_dict.insert "A" 1 . insert "A" 2 . get "A" . should_equal 2 - - group_builder.specify "should be able to remove entries" pending=pending_python_missing <| - py_dict_from_vec ["A", 1, "B", 2] . remove "A" . size . should_equal 1 - py_dict_from_vec ["A", 1, "B", 2] . remove "A" . get "B" . should_equal 2 - - group_builder.specify "should be able to remove NaN keys" pending=pending_python_missing <| - py_dict_from_vec [Number.nan, 1] . remove Number.nan . size . should_equal 0 - - group_builder.specify "should pass maps with null keys to Python and back" pending=pending_python_missing <| - # Python supports None as keys, Enso support Nothing as keys - py_dict = py_dict_from_map (Map.singleton Nothing 42) - py_dict.get Nothing . should_equal 42 - py_dict.insert "A" 23 . get Nothing . should_equal 42 - py_dict.insert Nothing 23 . get Nothing . should_equal 23 - - group_builder.specify "should treat Enso maps as Python dicts when passed to Python" pending=pending_python_missing <| - map1 = Map.empty.insert "A" 1 . insert "B" 2 - py_vec_from_map map1 . should_contain_the_same_elements_as [["A", 1], ["B", 2]] - map2 = Map.empty.insert "A" 1 . insert Nothing 2 - py_vec_from_map map2 . should_contain_the_same_elements_as [["A", 1], [Nothing, 2]] - - -add_common_specs suite_builder prefix:Text (pending : (Text | Nothing)) (empty_map_fn : (Nothing -> Map)) = - # Not on a single line - empty_map is a method, not a variable - empty_map = - empty_map_fn Nothing - - suite_builder.group prefix+": Common polyglot Map operations" pending=pending group_builder-> - group_builder.specify "should get the default comparator for polyglot maps" <| - Comparable.from empty_map . should_equal Default_Comparator - - group_builder.specify "should compare two hash maps" <| - (empty_map.insert "a" 1).should_equal (empty_map.insert "a" 1) - (empty_map.insert "b" 2).should_not_equal (empty_map.insert "a" 1) - empty_map.should_equal empty_map - empty_map.should_not_equal (empty_map.insert "a" 1) - (empty_map.insert "a" 1 . insert "b" 2).should_equal (empty_map.insert "b" 2 . insert "a" 1) - - group_builder.specify "should allow checking for non emptiness" <| - non_empty = empty_map . insert "foo" 1234 - empty_map.not_empty . should_be_false - non_empty.not_empty . should_be_true - - group_builder.specify "should allow checking its size" <| - non_empty = empty_map.insert "a" "b" . insert "x" "y" - empty_map.size . should_equal 0 - non_empty.size . should_equal 2 - - group_builder.specify "should allow checking for emptiness" <| - non_empty = empty_map . insert "foo" 1234 - empty_map.is_empty . should_be_true - non_empty.is_empty . should_be_false - - group_builder.specify "should handle incomparable values as keys" <| - empty_map.insert Number.nan 1 . insert Number.nan 2 . get Number.nan . should_equal 2 - - group_builder.specify "should handle Nothing as values" <| - empty_map.insert 1 Nothing . at 1 . should_equal Nothing - empty_map.insert Nothing Nothing . at Nothing . should_equal Nothing - - group_builder.specify "should support rewriting values with same keys" <| - map = Map.empty.insert "a" 1 . insert "a" 42 - map.size.should_equal 1 - map.get "a" . should_equal 42 - - group_builder.specify "should allow storing atoms as values" <| - json = Json.parse '{"a": 1}' - pair = Pair.new "first" "second" - map = Map.empty.insert 0 json . insert 1 pair - map.get 0 . should_equal json - map.get 1 . should_equal pair - - group_builder.specify "should support NaN as keys" <| - empty_map.insert Number.nan 1 . contains_key Number.nan . should_be_true - empty_map.insert Number.nan 1 . values . should_equal [1] - empty_map.insert Number.nan 1 . insert Number.nan 2 . contains_key Number.nan . should_be_true - empty_map.insert Number.nan 1 . insert Number.nan 2 . values . should_equal [2] - empty_map.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . contains_key Number.nan . should_be_true - empty_map.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . contains_key "key" . should_be_true - empty_map.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . at Number.nan . should_equal 3 - empty_map.insert Number.nan 1 . insert "key" 2 . insert Number.nan 3 . at "key" . should_equal 2 - empty_map.insert Number.nan 1 . insert Number.nan Number.nan . at Number.nan . to_text . should_equal "NaN" - empty_map.insert Number.nan 1 . insert Number.nan Number.nan . remove Number.nan . size . should_equal 0 - - group_builder.specify "should support arbitrary atoms as keys" <| - map = empty_map . insert (Pair.new "one" "two") 42 - (map.get (Pair.new "one" "two")).should_equal 42 - (map.get (Pair.new "A" "B")).should_equal Nothing - (map.get (Pair.new "two" "two")).should_equal Nothing - - group_builder.specify "should support vectors as keys" <| - map = empty_map . insert [1, "a", 2] "Value" - map.size.should_equal 1 - map.get [1, "a", 2] . should_equal "Value" - - group_builder.specify "should support dates as keys" <| - map = empty_map.insert (Date.new 1993) 1 . insert (Date.new 1993 2 5) 2 . insert (Date_Time.new 1993 2 5 13 45) 3 - map.size.should_equal 3 - map.get (Date.new 1993 6 7) . should_equal Nothing - map.get (Date.new 1993) . should_equal 1 - map.get (Date_Time.new 1993) . should_equal Nothing - map.get (Date.new 1993 2 5) . should_equal 2 - map.get (Date_Time.new 1993 2 5) . should_equal Nothing - map.get (Date_Time.new 1993 2 5 13 45) . should_equal 3 - - group_builder.specify "should support another hash map as key" <| - key_map = empty_map.insert (Pair.new "one" "two") 42 - map = empty_map.insert key_map 23 - map.size.should_equal 1 - (map.get "A").should_equal Nothing - (map.get key_map).should_equal 23 - (map.get map).should_equal Nothing - - group_builder.specify "should handle keys with standard equality semantics" <| - map = empty_map.insert 2 "Hello" - (map.get 2).should_equal "Hello" - (map.get 2.0).should_equal "Hello" - (empty_map.insert 2 "Hello").should_equal (empty_map.insert 2.0 "Hello") - - group_builder.specify "should handle Nothing as keys" <| - empty_map.insert Nothing 3 . get Nothing . should_equal 3 - empty_map.insert Nothing 1 . insert Nothing 2 . get Nothing . should_equal 2 - empty_map.insert Nothing 1 . should_equal (empty_map.insert Nothing 1) - empty_map.insert Nothing 1 . insert Nothing 2 . at Nothing . should_equal 2 - - group_builder.specify "should handle JavaScript null as keys" <| - empty_map.insert js_null 1 . at Nothing . should_equal 1 - - group_builder.specify "should handle Python None as keys" pending=pending_python_missing <| - empty_map.insert py_none 1 . at Nothing . should_equal 1 - - group_builder.specify "should define a well-defined text conversion" <| - m = empty_map . insert 0 0 . insert 3 -5 . insert 1 2 - m.to_text . should_contain "0=0" - m.to_text . should_contain "3=-5" - m.to_text . should_contain "1=2" - - group_builder.specify "should define structural equality" <| - map_1 = empty_map . insert "1" 2 . insert "2" "1" - map_2 = empty_map . insert "1" 2 . insert "2" "1" - map_3 = empty_map - map_1==map_2 . should_be_true - map_1==map_3 . should_be_false - map_2==map_3 . should_be_false - - group_builder.specify "should allow inserting and looking up values" <| - m = empty_map . insert "foo" 134 . insert "bar" 654 . insert "baz" "spam" - m.at "foo" . should_equal 134 - m.at "bar" . should_equal 654 - m.at "baz" . should_equal "spam" - (m.at "nope").should_fail_with No_Such_Key - - group_builder.specify "should support get" <| - m = empty_map . insert 2 3 - m.get 2 0 . should_equal 3 - m.get 1 10 . should_equal 10 - m.get 2 (Panic.throw "missing") . should_equal 3 - - group_builder.specify "should allow getting a vector of the keys" <| - m = empty_map . insert 1 2 . insert 2 4 - m.keys . should_equal [1, 2] - - group_builder.specify "should allow getting a vector of the values" <| - m = empty_map . insert 1 2 . insert 2 4 - m.values . should_equal [2, 4] - - group_builder.specify "should support contains_key" <| - m = empty_map . insert 2 3 - m.contains_key 2 . should_be_true - m.contains_key 1 . should_be_false - - group_builder.specify "should allow transforming the map" <| - m = empty_map . insert 1 2 . insert 2 4 - expected = empty_map . insert "1" 4 . insert "2" 8 - m.transform (k -> v -> [k.to_text, v*2]) . should_equal expected - - group_builder.specify "should be able to remove entries (1)" <| - m1 = empty_map.insert "A" 1 . insert "B" 2 - m2 = m1.remove "B" - m2.get "A" . should_equal 1 - m2.remove "A" . should_equal empty_map - m1.remove "foo" . should_fail_with No_Such_Key - - group_builder.specify "should be able to remove entries (2)" <| - m1 = empty_map.insert "A" 1 - m2 = m1.insert "B" 2 - m3 = m1.insert "C" 3 - m2.remove "A" . to_vector . should_equal [["B", 2]] - m2.remove "B" . to_vector . should_equal [["A", 1]] - m3.remove "A" . to_vector . should_equal [["C", 3]] - m3.remove "C" . to_vector . should_equal [["A", 1]] - - group_builder.specify "should be able to remove entries (3)" <| - m = empty_map.insert "A" 1 . insert "B" 2 . insert "C" 3 - m.remove "B" . should_equal (empty_map.insert "A" 1 . insert "C" 3) - - -main filter=Nothing = - suite = Test.build suite_builder-> - add_specs suite_builder - suite.run_with_filter filter diff --git a/test/Base_Tests/src/Data/Text/Regex_Spec.enso b/test/Base_Tests/src/Data/Text/Regex_Spec.enso index 258596496ae..e7ce093c359 100644 --- a/test/Base_Tests/src/Data/Text/Regex_Spec.enso +++ b/test/Base_Tests/src/Data/Text/Regex_Spec.enso @@ -393,7 +393,7 @@ add_specs suite_builder = group_builder.specify "should provide access to info about group names" <| data.pattern.named_groups.sort . should_equal ["empty", "letters"] - data.pattern.group_nums_to_names . should_equal <| Map.from_vector [[2, "letters"],[4, "empty"]] + data.pattern.group_nums_to_names . should_equal <| Dictionary.from_vector [[2, "letters"],[4, "empty"]] group_builder.specify "should return the results of all named groups" <| groups = data.match.named_groups diff --git a/test/Base_Tests/src/Data/XML/XML_Spec.enso b/test/Base_Tests/src/Data/XML/XML_Spec.enso index 25a9cde16a2..4cd5ea95b7a 100644 --- a/test/Base_Tests/src/Data/XML/XML_Spec.enso +++ b/test/Base_Tests/src/Data/XML/XML_Spec.enso @@ -133,8 +133,8 @@ add_specs suite_builder = data.root.at 3 . attribute "does_not_exist" if_missing="if_missing" . should_equal "if_missing" group_builder.specify "Can get element an attribute map" <| - data.root.at 2 . attributes . should_equal (Map.from_vector [["studentId", "1000"], ["year", "2"]]) - data.root.at 3 . attributes . should_equal (Map.from_vector [["studentId", "1001"], ["year", "3"]]) + data.root.at 2 . attributes . should_equal (Dictionary.from_vector [["studentId", "1000"], ["year", "2"]]) + data.root.at 3 . attributes . should_equal (Dictionary.from_vector [["studentId", "1001"], ["year", "3"]]) group_builder.specify "Can get nodes via xpath" <| classes = data.root.get_xpath "/class" diff --git a/test/Base_Tests/src/Main.enso b/test/Base_Tests/src/Main.enso index 80e6ef96205..341bd982037 100644 --- a/test/Base_Tests/src/Main.enso +++ b/test/Base_Tests/src/Main.enso @@ -30,12 +30,13 @@ import project.Data.Array_Proxy_Spec import project.Data.Bool_Spec import project.Data.Base_64_Spec import project.Data.Decimal_Spec +import project.Data.Dictionary_Spec import project.Data.Function_Spec +import project.Data.Hashset_Spec import project.Data.Interval_Spec import project.Data.Json_Spec import project.Data.List_Spec import project.Data.Locale_Spec -import project.Data.Map_Spec import project.Data.Maybe_Spec import project.Data.Numbers_Spec import project.Data.Ordering_Spec @@ -47,7 +48,6 @@ import project.Data.Polyglot_Spec import project.Data.Problems_Spec import project.Data.Range_Spec import project.Data.Regression_Spec -import project.Data.Set_Spec import project.Data.Statistics_Spec import project.Data.Time.Spec as Time_Spec import project.Data.Vector_Spec @@ -129,8 +129,8 @@ main filter=Nothing = Json_Spec.add_specs suite_builder List_Spec.add_specs suite_builder Locale_Spec.add_specs suite_builder - Map_Spec.add_specs suite_builder - Set_Spec.add_specs suite_builder + Dictionary_Spec.add_specs suite_builder + Hashset_Spec.add_specs suite_builder Maybe_Spec.add_specs suite_builder Meta_Spec.add_specs suite_builder Instrumentor_Spec.add_specs suite_builder diff --git a/test/Base_Tests/src/Network/Http/Request_Spec.enso b/test/Base_Tests/src/Network/Http/Request_Spec.enso index 59fb5b75eac..a3b80d2a076 100644 --- a/test/Base_Tests/src/Network/Http/Request_Spec.enso +++ b/test/Base_Tests/src/Network/Http/Request_Spec.enso @@ -42,7 +42,7 @@ add_specs suite_builder = req.body.should_equal (Request_Body.Json json) req.headers.should_equal [Header.application_json] group_builder.specify "should set form body" <| - body_form = Map.from_vector [["key", "val"]] + body_form = Dictionary.from_vector [["key", "val"]] req = Request.get test_uri . with_form body_form req.body.should_equal (Request_Body.Form_Data body_form) req.headers.should_equal [Header.application_x_www_form_urlencoded] diff --git a/test/Base_Tests/src/Network/Http_Spec.enso b/test/Base_Tests/src/Network/Http_Spec.enso index 325e2a0dc14..b4db06920cc 100644 --- a/test/Base_Tests/src/Network/Http_Spec.enso +++ b/test/Base_Tests/src/Network/Http_Spec.enso @@ -288,14 +288,14 @@ add_specs suite_builder = group_builder.specify "Can perform a url-encoded form POST" <| Test.with_retries <| test_file = enso_project.data / "sample.txt" - form_data = Map.from_vector [["key", "val"], ["a_file", test_file]] + form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]] response = Data.post url_post (Request_Body.Form_Data form_data url_encoded=True) response.at "headers" . at "Content-Type" . should_equal "application/x-www-form-urlencoded" response.at "data" . replace "%0D%" "%" . should_equal 'key=val&a_file=Cupcake+ipsum+dolor+sit+amet.+Caramels+tootsie+roll+cake+ice+cream.+Carrot+cake+apple+pie+gingerbread+chocolate+cake+pudding+tart+souffl%C3%A9+jelly+beans+gummies.%0A%0ATootsie+roll+chupa+chups+muffin+croissant+fruitcake+jujubes+danish+cotton+candy+danish.+Oat+cake+chocolate+fruitcake+halvah+icing+oat+cake+toffee+powder.+Pastry+drag%C3%A9e+croissant.+Ice+cream+candy+canes+dessert+muffin+sugar+plum+tart+jujubes.%0A' group_builder.specify "Can perform a multipart form POST" <| Test.with_retries <| test_file = enso_project.data / "sample.png" - form_data = Map.from_vector [["key", "val"], ["a_file", test_file]] + form_data = Dictionary.from_vector [["key", "val"], ["a_file", test_file]] response = Data.post url_post (Request_Body.Form_Data form_data) response_json = response response_json.at "headers" . at "Content-Type" . should_start_with "multipart/form-data; boundary=" diff --git a/test/Benchmarks/src/Collections.enso b/test/Benchmarks/src/Collections.enso index 462078c3c06..6e0850f91b8 100644 --- a/test/Benchmarks/src/Collections.enso +++ b/test/Benchmarks/src/Collections.enso @@ -20,7 +20,7 @@ sum_recur n = if n == 0 then 0 else 1 + sum_recur n-1 build_map size = rand = Java_Random.new - 0.up_to size . fold Map.empty (m -> i -> m.insert (rand.nextInt 10000) i) + 0.up_to size . fold Dictionary.empty (m -> i -> m.insert (rand.nextInt 10000) i) type Data Value ~list ~vec ~vec_float diff --git a/test/Benchmarks/src/Map/Hash_Map.enso b/test/Benchmarks/src/Map/Hash_Map.enso index e56b9340e62..743336cb3fb 100644 --- a/test/Benchmarks/src/Map/Hash_Map.enso +++ b/test/Benchmarks/src/Map/Hash_Map.enso @@ -44,13 +44,13 @@ collect_benches = Bench.build builder-> builder.group ("Enso_Hash_Map_" + n.to_text) options group_builder-> # Scenario similar to what is done in distinct group_builder.specify "Enso_Incremental" <| - Scenario.Instance (_ -> Map.empty) . run_distinct data.ints + Scenario.Instance (_ -> Dictionary.empty) . run_distinct data.ints group_builder.specify "Java_Incremental" <| Scenario.Instance (_ -> JavaHashMapWrapper.new) . run_distinct data.ints # A scenario similar to what is done in add_row_number with grouping group_builder.specify "Enso_Replacement" <| - Scenario.Instance (_ -> Map.empty) . run_count_keys data.ints + Scenario.Instance (_ -> Dictionary.empty) . run_count_keys data.ints group_builder.specify "Java_Replacement" <| Scenario.Instance (_ -> JavaHashMapWrapper.new) . run_count_keys data.ints diff --git a/test/Examples_Tests/src/Examples_Spec.enso b/test/Examples_Tests/src/Examples_Spec.enso index 60221572dc5..633d0d10a9f 100644 --- a/test/Examples_Tests/src/Examples_Spec.enso +++ b/test/Examples_Tests/src/Examples_Spec.enso @@ -49,8 +49,8 @@ add_specs suite_builder = suite_builder.group "Examples" group_builder-> group_builder.specify "should provide a basic cons list" <| Examples.list.length . should_equal 3 - group_builder.specify "should provide a basic KV map" <| - Examples.map.size . should_equal 3 + group_builder.specify "should provide a basic KV dictionary" <| + Examples.dictionary.size . should_equal 3 group_builder.specify "should provide a type with no methods" <| Examples.No_Methods.should_be_a Examples.No_Methods diff --git a/test/Snowflake_Tests/src/Snowflake_Spec.enso b/test/Snowflake_Tests/src/Snowflake_Spec.enso index 1a6591feea0..021cdcfafa2 100644 --- a/test/Snowflake_Tests/src/Snowflake_Spec.enso +++ b/test/Snowflake_Tests/src/Snowflake_Spec.enso @@ -583,14 +583,14 @@ add_snowflake_specs suite_builder create_connection_fn db_name = Common_Table_Operations.Main.add_specs suite_builder setup ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e0 = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive False] e1 = [Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive False, Replace_Params.Value Text Case_Sensitivity.Insensitive True] e2 = [Replace_Params.Value Regex Case_Sensitivity.Default False, Replace_Params.Value Regex Case_Sensitivity.Default True, Replace_Params.Value Regex Case_Sensitivity.Sensitive False] e3 = [Replace_Params.Value Regex Case_Sensitivity.Sensitive True, Replace_Params.Value Regex Case_Sensitivity.Insensitive False, Replace_Params.Value Regex Case_Sensitivity.Insensitive True] e4 = [Replace_Params.Value DB_Column Case_Sensitivity.Default False, Replace_Params.Value DB_Column Case_Sensitivity.Sensitive False] - Set.from_vector <| e0 + e1 + e2 + e3 + e4 + Hashset.from_vector <| e0 + e1 + e2 + e3 + e4 add_table_specs suite_builder = case create_connection_builder of diff --git a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso index a16a7de1ce6..a0254c3e996 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso @@ -1297,7 +1297,7 @@ add_specs suite_builder setup = input_type = Meta.type_of term params = Replace_Params.Value input_type case_sensitivity only_first supported_replace_params = setup.test_selection.supported_replace_params - supported_replace_params . should_be_a Set + supported_replace_params . should_be_a Hashset are_params_supported = supported_replace_params.contains params case are_params_supported of True -> column.text_replace term new_text case_sensitivity only_first . to_vector . should_equal expected diff --git a/test/Table_Tests/src/Common_Table_Operations/Cross_Tab_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Cross_Tab_Spec.enso index 8a2debbc561..2ea73445388 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Cross_Tab_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Cross_Tab_Spec.enso @@ -186,7 +186,7 @@ add_specs suite_builder setup = problems = [Duplicate_Output_Column_Names.Error ["x Agg1", "y Agg1", "z Agg1"]] Problems.test_problem_handling action problems tester - table3 = data.table2.rename_columns (Map.from_vector [["Group", "x"]]) + table3 = data.table2.rename_columns (Dictionary.from_vector [["Group", "x"]]) action3 = table3.cross_tab ["x"] "Key" on_problems=_ tester3 table = table.column_names . should_equal ["x", "x 1", "y", "z"] diff --git a/test/Table_Tests/src/Common_Table_Operations/Join/Replace_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Join/Replace_Spec.enso index e0ef668dbdd..516896c69d5 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Join/Replace_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Join/Replace_Spec.enso @@ -56,7 +56,7 @@ add_specs suite_builder setup = group_builder.specify "should be able to replace values via a lookup table provided as a Map" <| table = table_builder [['x', [1, 2, 3, 4, 2]], ['y', ['a', 'b', 'c', 'd', 'e']]] - lookup_table = Map.from_vector [[2, 20], [1, 10], [4, 40], [3, 30]] + lookup_table = Dictionary.from_vector [[2, 20], [1, 10], [4, 40], [3, 30]] expected = table_builder [['x', [10, 20, 20, 30, 40]], ['y', ['a', 'b', 'e', 'c', 'd']]] result = table.replace lookup_table 'x' . sort ["x", "y"] result . should_equal expected @@ -158,25 +158,25 @@ add_specs suite_builder setup = group_builder.specify "should accept an empty lookup map, if allow_unmatched_rows=True, but expect a warning" <| table = table_builder [['x', [1, 2, 3, 4, 2]], ['y', ['a', 'b', 'c', 'd', 'e']]] - t = table.replace Map.empty 'x' + t = table.replace Dictionary.empty 'x' t . should_equal table Problems.expect_warning (Empty_Error.Error "lookup_table") t group_builder.specify "should throw an error on an empty lookup map and non-empty base table if allow_unmatched_rows=False" <| table = table_builder [['x', [1, 2, 3, 4, 2]], ['y', ['a', 'b', 'c', 'd', 'e']]] . sort ['x'] - t = table.replace Map.empty 'x' allow_unmatched_rows=False + t = table.replace Dictionary.empty 'x' allow_unmatched_rows=False t . should_fail_with Unmatched_Rows_In_Lookup t.catch.example_key_values . should_equal [1] group_builder.specify "should accept an empty lookup map if the base table is also empty, but expect a warning" <| table = table_builder_typed [['x', []], ['z', []]] Value_Type.Integer - t = table.replace Map.empty 'x' + t = table.replace Dictionary.empty 'x' t . should_equal table Problems.expect_warning (Empty_Error.Error "lookup_table") t group_builder.specify "should not allow from/to_coumn to specified if the argument is a Map" <| table = table_builder [['x', [1, 2, 3, 4, 2]], ['y', ['a', 'b', 'c', 'd', 'e']]] - lookup_table = Map.from_vector [[2, 20], [1, 10], [4, 40], [3, 30]] + lookup_table = Dictionary.from_vector [[2, 20], [1, 10], [4, 40], [3, 30]] table.replace lookup_table 'x' from_column=8 . should_fail_with Illegal_Argument table.replace lookup_table 'x' to_column=9 . should_fail_with Illegal_Argument table.replace lookup_table 'x' from_column=8 to_column=9 . should_fail_with Illegal_Argument diff --git a/test/Table_Tests/src/Common_Table_Operations/Map_To_Table_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Map_To_Table_Spec.enso index fce64c0f2ca..03c33b6f75f 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Map_To_Table_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Map_To_Table_Spec.enso @@ -28,7 +28,7 @@ type Data add_specs suite_builder setup = prefix = setup.prefix create_connection_fn = setup.create_connection_func - suite_builder.group prefix+"Table.make_table_from_map/vectors" group_builder-> + suite_builder.group prefix+"Table.make_table_from_dictionary/vectors" group_builder-> data = Data.setup setup create_connection_fn group_builder.teardown <| @@ -66,21 +66,21 @@ add_specs suite_builder setup = vecs2 = [[], [3, 4, 5], [6, 7, 8]] data.dummy_table.make_table_from_vectors vecs2 ['x', 'y', 'z'] . read . should_fail_with Illegal_Argument - group_builder.specify "should be able to create a literal table from a map" <| - map = Map.from_vector [['x', 1], ['y', 2], ['z', 3]] - t = data.dummy_table.make_table_from_map map 'k' 'v' . sort 'v' + group_builder.specify "should be able to create a literal table from a dictionary" <| + map = Dictionary.from_vector [['x', 1], ['y', 2], ['z', 3]] + t = data.dummy_table.make_table_from_dictionary map 'k' 'v' . sort 'v' t.at 'k' . to_vector . should_equal ['x', 'y', 'z'] t.at 'v' . to_vector . should_equal [1, 2, 3] if setup.is_database then - group_builder.specify "should not be able to create a literal table from an empty map" <| - map = Map.empty - data.dummy_table.make_table_from_map map 'k' 'v' . should_fail_with Illegal_Argument + group_builder.specify "should not be able to create a literal table from an empty dictionary" <| + map = Dictionary.empty + data.dummy_table.make_table_from_dictionary map 'k' 'v' . should_fail_with Illegal_Argument if setup.is_database.not then - group_builder.specify "should be able to create a literal table from an empty map" <| - map = Map.empty - t = data.dummy_table.make_table_from_map map 'k' 'v' + group_builder.specify "should be able to create a literal table from an empty dictionary" <| + map = Dictionary.empty + t = data.dummy_table.make_table_from_dictionary map 'k' 'v' t.row_count . should_equal 0 if setup.is_database then diff --git a/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso index e2df843fd36..d192b82e516 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso @@ -481,10 +481,10 @@ add_specs suite_builder setup = t1 = table_builder [["alpha", [1]], ["name=123", [2]], ["name= foo bar", [3]]] expect_column_names ["alpha", "key:123", "key: foo bar"] <| - t1.rename_columns (Map.from_vector [["name=(.*)".to_regex, "key:$1"]]) + t1.rename_columns (Dictionary.from_vector [["name=(.*)".to_regex, "key:$1"]]) group_builder.specify "should work by index" <| - map = Map.from_vector [[0, "FirstColumn"], [-2, "Another"]] + map = Dictionary.from_vector [[0, "FirstColumn"], [-2, "Another"]] expect_column_names ["FirstColumn", "beta", "Another", "delta"] <| data.table.rename_columns map @@ -504,12 +504,12 @@ add_specs suite_builder setup = data.table.rename_columns vec group_builder.specify "should work by name" <| - map = Map.from_vector [["alpha", "FirstColumn"], ["delta", "Another"]] + map = Dictionary.from_vector [["alpha", "FirstColumn"], ["delta", "Another"]] expect_column_names ["FirstColumn", "beta", "gamma", "Another"] <| data.table.rename_columns map group_builder.specify "should work by mixed Map" <| - map = Map.from_vector [["alpha", "FirstColumn"], [-1, "Another"]] + map = Dictionary.from_vector [["alpha", "FirstColumn"], [-1, "Another"]] expect_column_names ["FirstColumn", "beta", "gamma", "Another"] <| data.table.rename_columns map @@ -552,17 +552,17 @@ add_specs suite_builder setup = fail_2.catch.message.should_contain "materialize" group_builder.specify "should work by name case-insensitively" <| - map = Map.from_vector [["ALPHA", "FirstColumn"], ["DELTA", "Another"]] + map = Dictionary.from_vector [["ALPHA", "FirstColumn"], ["DELTA", "Another"]] expect_column_names ["FirstColumn", "beta", "gamma", "Another"] <| data.table.rename_columns map Case_Sensitivity.Insensitive group_builder.specify "should work by name using regex" <| - map = Map.from_vector [["a.*".to_regex, "FirstColumn"]] + map = Dictionary.from_vector [["a.*".to_regex, "FirstColumn"]] expect_column_names ["FirstColumn", "beta", "gamma", "delta"] <| data.table.rename_columns map group_builder.specify "should work by name using regex substitution" <| - map = Map.from_vector [["a(.*)".to_regex, "$1"]] + map = Dictionary.from_vector [["a(.*)".to_regex, "$1"]] expect_column_names ["lpha", "beta", "gamma", "delta"] <| data.table.rename_columns map @@ -591,7 +591,7 @@ add_specs suite_builder setup = group_builder.specify "should correctly handle problems: unmatched names" <| weird_name = '.*?-!@#!"' - map = Map.from_vector [["alpha", "FirstColumn"], ["omicron", "Another"], [weird_name, "Fixed"]] + map = Dictionary.from_vector [["alpha", "FirstColumn"], ["omicron", "Another"], [weird_name, "Fixed"]] action = data.table.rename_columns map error_on_missing_columns=False on_problems=_ tester = expect_column_names ["FirstColumn", "beta", "gamma", "delta"] err_checker err = @@ -603,7 +603,7 @@ add_specs suite_builder setup = err.should_fail_with Missing_Input_Columns group_builder.specify "should correctly handle problems: out of bounds indices" <| - map = Map.from_vector [[0, "FirstColumn"], [-1, "Another"], [100, "Boo"], [-200, "Nothing"], [300, "Here"]] + map = Dictionary.from_vector [[0, "FirstColumn"], [-1, "Another"], [100, "Boo"], [-200, "Nothing"], [300, "Here"]] action = data.table.rename_columns map error_on_missing_columns=False on_problems=_ tester = expect_column_names ["FirstColumn", "beta", "gamma", "Another"] err_checker err = @@ -615,12 +615,12 @@ add_specs suite_builder setup = err.should_fail_with Missing_Input_Columns group_builder.specify "should correctly handle edge-cases: aliased indices" <| - map1 = Map.from_vector [[1, "FirstColumn"], [-3, "FirstColumn"]] + map1 = Dictionary.from_vector [[1, "FirstColumn"], [-3, "FirstColumn"]] t1 = data.table.rename_columns map1 on_problems=..Report_Error Problems.assume_no_problems t1 expect_column_names ["alpha", "FirstColumn", "gamma", "delta"] t1 - map2 = Map.from_vector [[1, "FirstColumn"], [-3, "DifferentName!"]] + map2 = Dictionary.from_vector [[1, "FirstColumn"], [-3, "DifferentName!"]] t2 = data.table.rename_columns map2 on_problems=..Report_Error t2.should_fail_with Ambiguous_Column_Rename err = t2.catch . inner_error @@ -629,12 +629,12 @@ add_specs suite_builder setup = group_builder.specify "should correctly handle edge-cases: aliased selectors" <| t = table_builder [["alpha", [1,2,3]], ["bet", [4,5,6]]] - map1 = Map.from_vector [["a.*".to_regex, "AA"], [".*a".to_regex, "AA"]] + map1 = Dictionary.from_vector [["a.*".to_regex, "AA"], [".*a".to_regex, "AA"]] t1 = t.rename_columns map1 on_problems=..Report_Error Problems.assume_no_problems t1 expect_column_names ["AA", "bet"] t1 - map2 = Map.from_vector [["a.*".to_regex, "StartsWithA"], [".*a".to_regex, "EndsWithA"]] + map2 = Dictionary.from_vector [["a.*".to_regex, "StartsWithA"], [".*a".to_regex, "EndsWithA"]] t2 = t.rename_columns map2 on_problems=..Report_Error t2.should_fail_with Ambiguous_Column_Rename err = t2.catch . inner_error @@ -647,13 +647,13 @@ add_specs suite_builder setup = This is to show that even if distinct rename patterns match the same column, if the resulting rename is unambiguous, no error is raised. - map3 = Map.from_vector [["a(.*)".to_regex, "$1A"], ["(.*)aa".to_regex, "$1aA"]] + map3 = Dictionary.from_vector [["a(.*)".to_regex, "$1A"], ["(.*)aa".to_regex, "$1aA"]] t4 = t3.rename_columns map3 on_problems=..Report_Error Problems.assume_no_problems t4 expect_column_names ["aaA", "bbb"] t4 group_builder.specify "should correctly handle problems: invalid names ''" <| - map = Map.from_vector [[1, ""]] + map = Dictionary.from_vector [[1, ""]] [Problem_Behavior.Ignore, Problem_Behavior.Report_Warning, Problem_Behavior.Report_Error].each pb-> r = data.table.rename_columns map on_problems=pb r.should_fail_with Invalid_Column_Names @@ -678,13 +678,13 @@ add_specs suite_builder setup = Problems.test_problem_handling action problems tester group_builder.specify "should correctly handle problems: new name is clashing with existing name of existing column" <| - map = Map.from_vector [["alpha", "beta"]] + map = Dictionary.from_vector [["alpha", "beta"]] action = data.table.rename_columns map on_problems=_ tester = expect_column_names ["beta", "beta 1", "gamma", "delta"] problems = [Duplicate_Output_Column_Names.Error ["beta"]] Problems.test_problem_handling action problems tester - map2 = Map.from_vector [["beta", "alpha"]] + map2 = Dictionary.from_vector [["beta", "alpha"]] action2 = data.table.rename_columns map2 on_problems=_ tester2 = expect_column_names ["alpha 1", "alpha", "gamma", "delta"] problems2 = [Duplicate_Output_Column_Names.Error ["alpha"]] diff --git a/test/Table_Tests/src/Database/Postgres_Spec.enso b/test/Table_Tests/src/Database/Postgres_Spec.enso index 2f00c1e34f1..74c4cc702da 100644 --- a/test/Table_Tests/src/Database/Postgres_Spec.enso +++ b/test/Table_Tests/src/Database/Postgres_Spec.enso @@ -211,7 +211,7 @@ postgres_specific_spec suite_builder create_connection_fn db_name setup = column/table names and their lengths, this should not be a big problem usually, so only a warning is issued. It may however lead to data integrity issues in some very rare edge cases. - unsupported_encodings = Set.from_vector <| + unsupported_encodings = Hashset.from_vector <| ["EUC_JIS_2004", "LATIN6", "LATIN8", "MULE_INTERNAL", "SHIFT_JIS_2004"] known_encodings.each encoding_name-> @@ -706,14 +706,14 @@ add_postgres_specs suite_builder create_connection_fn db_name = Common_Table_Operations.Main.add_specs suite_builder setup ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e0 = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive False] e1 = [Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive False, Replace_Params.Value Text Case_Sensitivity.Insensitive True] e2 = [Replace_Params.Value Regex Case_Sensitivity.Default False, Replace_Params.Value Regex Case_Sensitivity.Default True, Replace_Params.Value Regex Case_Sensitivity.Sensitive False] e3 = [Replace_Params.Value Regex Case_Sensitivity.Sensitive True, Replace_Params.Value Regex Case_Sensitivity.Insensitive False, Replace_Params.Value Regex Case_Sensitivity.Insensitive True] e4 = [Replace_Params.Value DB_Column Case_Sensitivity.Default False, Replace_Params.Value DB_Column Case_Sensitivity.Sensitive False] - Set.from_vector <| e0 + e1 + e2 + e3 + e4 + Hashset.from_vector <| e0 + e1 + e2 + e3 + e4 add_table_specs suite_builder = db_name = Environment.get "ENSO_POSTGRES_DATABASE" diff --git a/test/Table_Tests/src/Database/SQLite_Spec.enso b/test/Table_Tests/src/Database/SQLite_Spec.enso index 4999f99fc35..313dbca7fff 100644 --- a/test/Table_Tests/src/Database/SQLite_Spec.enso +++ b/test/Table_Tests/src/Database/SQLite_Spec.enso @@ -356,10 +356,10 @@ sqlite_spec suite_builder prefix create_connection_func = ## PRIVATE -supported_replace_params : Set Replace_Params +supported_replace_params : Hashset Replace_Params supported_replace_params = e = [Replace_Params.Value Text Case_Sensitivity.Default False, Replace_Params.Value Text Case_Sensitivity.Sensitive False, Replace_Params.Value Text Case_Sensitivity.Default True, Replace_Params.Value Text Case_Sensitivity.Sensitive True, Replace_Params.Value Text Case_Sensitivity.Insensitive True] - Set.from_vector e + Hashset.from_vector e ## Reference to the database file that ensures the first test that uses it will clean any leftover files from earlier runs. diff --git a/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso b/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso index 10b744a68f1..6319d17cbdb 100644 --- a/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso +++ b/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso @@ -123,8 +123,8 @@ add_specs suite_builder = group_builder.specify "should be able to infer types for all supported operations" <| dialect = Dialect.sqlite - internal_mapping = dialect.dialect_operations.operation_map - operation_type_mapping = SQLite_Type_Mapping.operations_map + internal_mapping = dialect.dialect_operations.operations_dict + operation_type_mapping = SQLite_Type_Mapping.operations_dict operation_type_mapping.keys.sort . should_equal internal_mapping.keys.sort diff --git a/test/Table_Tests/src/Database/Upload_Spec.enso b/test/Table_Tests/src/Database/Upload_Spec.enso index 7ed12d75321..ac17a67bf71 100644 --- a/test/Table_Tests/src/Database/Upload_Spec.enso +++ b/test/Table_Tests/src/Database/Upload_Spec.enso @@ -562,7 +562,7 @@ add_specs suite_builder make_new_connection prefix persistent_connector=True = e2.clashing_example_key_values.length . should_equal 1 x = e2.clashing_example_key_values.first [1, 2, 3].should_contain x - counts = Map.from_vector [[1, 2], [2, 4], [3, 2]] + counts = Dictionary.from_vector [[1, 2], [2, 4], [3, 2]] e2.clashing_example_row_count . should_equal (counts.at x) # Will not find clashes if they are not in the first 1000 rows, in Output disabled mode. @@ -1201,14 +1201,14 @@ test_table_append group_builder (data : Data) source_table_builder target_table_ ## If there are some additional tables, we add some timeout to allow the database to do the cleaning up. - additional_tables = (Set.from_vector tables_immediately_after).difference (Set.from_vector existing_tables) + additional_tables = (Hashset.from_vector tables_immediately_after).difference (Hashset.from_vector existing_tables) if additional_tables.is_empty then Nothing else additional_table = additional_tables.to_vector.first wait_until_temporary_table_is_deleted_after_closing_connection data.connection additional_table # After the wait we check again and now there should be no additional tables. tables_after_wait = data.connection.base_connection.get_tables_advanced types=Nothing include_hidden=True . at "Name" . to_vector - additional_tables_2 = (Set.from_vector tables_after_wait).difference (Set.from_vector existing_tables) + additional_tables_2 = (Hashset.from_vector tables_after_wait).difference (Hashset.from_vector existing_tables) additional_tables_2.to_vector . should_equal [] diff --git a/test/Table_Tests/src/Helpers/Unique_Naming_Strategy_Spec.enso b/test/Table_Tests/src/Helpers/Unique_Naming_Strategy_Spec.enso index 46fe81a764c..f0412cfc10f 100644 --- a/test/Table_Tests/src/Helpers/Unique_Naming_Strategy_Spec.enso +++ b/test/Table_Tests/src/Helpers/Unique_Naming_Strategy_Spec.enso @@ -116,7 +116,7 @@ add_specs suite_builder = strategy.make_unique "abc" . should_equal "ab 10" strategy.make_unique "abc" . should_equal "ab 11" - strategy.truncated_names . should_be_a Map + strategy.truncated_names . should_be_a Dictionary strategy.truncated_names.get "abcdefgh" . should_equal "abcde" # abc will contain the entry for the last truncated case strategy.truncated_names.get "abc" . should_equal "ab 11" diff --git a/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso b/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso index 46e2ea94719..e49452f415a 100644 --- a/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso @@ -227,30 +227,30 @@ add_specs suite_builder = table.expand_column "cols" . should_equal expected group_builder.specify "will work even if keys are not Text" <| - table = Table.new [["a", [1, 2]], ["b", [Map.from_vector [[1, "x"], [2, "y"]], Map.from_vector [[2, "z"], [3, "w"]]]]] + table = Table.new [["a", [1, 2]], ["b", [Dictionary.from_vector [[1, "x"], [2, "y"]], Dictionary.from_vector [[2, "z"], [3, "w"]]]]] expected = Table.new [["a", [1, 2]], ["b 1", ["x", Nothing]], ["b 2", ["y", "z"]], ["b 3", [Nothing, "w"]]] table.expand_column "b" . should_equal expected - table2 = Table.new [["a", [1, 2]], ["b", [Map.from_vector [[My_Mod_Type.Value 12, "x"], [My_Mod_Type.Value 23, "y"]], Map.from_vector [[My_Mod_Type.Value 32, "z"]]]]] + table2 = Table.new [["a", [1, 2]], ["b", [Dictionary.from_vector [[My_Mod_Type.Value 12, "x"], [My_Mod_Type.Value 23, "y"]], Dictionary.from_vector [[My_Mod_Type.Value 32, "z"]]]]] expected2 = Table.new [["a", [1, 2]], ["b x%10=3", ["y", Nothing]], ["b x%10=2", ["x", "z"]]] table2.expand_column "b" . should_equal expected2 group_builder.specify "will fail if text representation of keys is not unique" <| k1 = My_Mod_Type.Value 12 k2 = My_Mod_Type.Value 32 - m = Map.from_vector [[k1, "a"], [k2, "b"]] + m = Dictionary.from_vector [[k1, "a"], [k2, "b"]] m.at k1 . should_equal "a" m.at k2 . should_equal "b" k1.to_text . should_equal "x%10=2" k2.to_text . should_equal "x%10=2" - table = Table.new [["a", [1, 2]], ["b", [Map.from_vector [[k1, "x"], [k2, "y"]] , Map.from_vector []]]] + table = Table.new [["a", [1, 2]], ["b", [Dictionary.from_vector [[k1, "x"], [k2, "y"]] , Dictionary.from_vector []]]] r = table.expand_column "b" r.should_fail_with Illegal_Argument r.catch.to_display_text . should_contain "keys are duplicated when converted to text" group_builder.specify "will error when all objects have no fields" <| - table = Table.new [["aaa", [1, 2]], ["bbb", [Map.from_vector [], Map.from_vector []]], ["ccc", [5, 6]]] + table = Table.new [["aaa", [1, 2]], ["bbb", [Dictionary.from_vector [], Dictionary.from_vector []]], ["ccc", [5, 6]]] r = table.expand_column "bbb" r.should_fail_with Illegal_Argument r.catch.message.should_contain "as all inputs had no fields" @@ -337,7 +337,7 @@ add_specs suite_builder = table.expand_to_rows "bbb" . should_equal expected group_builder.specify "Can expand Map" <| - values_to_expand = [Map.empty.insert "a" 10, Map.empty.insert "d" 40 . insert "b" 20, Map.empty.insert "c" 30] + values_to_expand = [Dictionary.singleton "a" 10, Dictionary.singleton "d" 40 . insert "b" 20, Dictionary.singleton "c" 30] table = Table.new [["aaa", [1, 2, 3]], ["bbb", values_to_expand], ["ccc", [5, 6, 7]]] expected = Table.new [["aaa", [1, 2, 2, 3]], ["bbb Key", ["a", "d", "b", "c"]], ["bbb", [10, 40, 20, 30]], ["ccc", [5, 6, 6, 7]]] table.expand_to_rows "bbb" . should_equal expected diff --git a/test/Table_Tests/src/In_Memory/Table_Spec.enso b/test/Table_Tests/src/In_Memory/Table_Spec.enso index da67d628ece..f742adb74a8 100644 --- a/test/Table_Tests/src/In_Memory/Table_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Table_Spec.enso @@ -905,7 +905,7 @@ add_specs suite_builder = if has_nulls then builder.append Nothing if has_true then builder.append True if has_false then builder.append False - in_vector_set = Set.from_vector in_vector + in_vector_set = Hashset.from_vector in_vector vectors = [[True, False, Nothing], [Nothing, Nothing, Nothing], [False, False, True], [True, True, True], [False, False, False], [Nothing, True, True], [False, Nothing, False]] vectors.each column_vector->