From d191e7a1a0f24215a318ae86b9e7a4fea301e763 Mon Sep 17 00:00:00 2001 From: Ian Hobson Date: Fri, 26 Jan 2024 10:22:46 +0100 Subject: [PATCH 1/3] Replace map.with_meta_map with set_meta, and rename get_meta_map to get_meta --- CHANGELOG.md | 2 ++ crates/runtime/src/core_lib/map.rs | 8 +++++--- crates/runtime/src/types/map.rs | 4 ++-- crates/runtime/tests/vm_tests.rs | 8 ++++---- docs/core_lib/map.md | 26 ++++++++++---------------- docs/language/meta_maps.md | 12 ++++++------ koto/tests/meta_maps.koto | 8 ++++---- libs/color/src/lib.rs | 2 +- 8 files changed, 34 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6cf27bf0..b2d9b7fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,8 @@ The Koto project adheres to exception being thrown. - Objects can be compared with `null` on the LHS without having to implement `KotoObject::equal` and/or `not_equal`. +- `map.with_meta_map` has been replaced with `set_meta`, and `get_meta_map` has + been renamed to `get_meta`. #### API diff --git a/crates/runtime/src/core_lib/map.rs b/crates/runtime/src/core_lib/map.rs index e7fcff5cc..98d4b5384 100644 --- a/crates/runtime/src/core_lib/map.rs +++ b/crates/runtime/src/core_lib/map.rs @@ -114,7 +114,7 @@ pub fn make_module() -> KMap { } }); - result.add_fn("get_meta_map", |ctx| { + result.add_fn("get_meta", |ctx| { let expected_error = "a Map"; match map_instance_and_args(ctx, expected_error)? { @@ -325,12 +325,14 @@ pub fn make_module() -> KMap { } }); - result.add_fn("with_meta_map", |ctx| { + result.add_fn("set_meta", |ctx| { let expected_error = "two Maps"; match map_instance_and_args(ctx, expected_error)? { (KValue::Map(data), [KValue::Map(meta)]) => { - Ok(KValue::Map(KMap::from_data_and_meta_maps(data, meta))) + let mut data = data.clone(); + data.set_meta_map(meta.meta_map().cloned()); + Ok(data.into()) } (_, unexpected) => type_error_with_slice(expected_error, unexpected), } diff --git a/crates/runtime/src/types/map.rs b/crates/runtime/src/types/map.rs index bbd2957ff..f97f05655 100644 --- a/crates/runtime/src/types/map.rs +++ b/crates/runtime/src/types/map.rs @@ -112,8 +112,8 @@ impl KMap { } /// Sets the KMap's meta map - pub fn set_meta_map(&mut self, meta: Option) { - self.meta = meta.map(PtrMut::from) + pub fn set_meta_map(&mut self, meta: Option>) { + self.meta = meta; } /// Returns true if the meta map contains an entry with the given key diff --git a/crates/runtime/tests/vm_tests.rs b/crates/runtime/tests/vm_tests.rs index 47d6c9489..87ec52c0b 100644 --- a/crates/runtime/tests/vm_tests.rs +++ b/crates/runtime/tests/vm_tests.rs @@ -2855,7 +2855,7 @@ catch _ fn arithmetic() { let script = " locals = {} -foo = |x| {x}.with_meta_map locals.foo_meta +foo = |x| {x}.set_meta locals.foo_meta locals.foo_meta = @+: |other| foo self.x + other.x @-: |other| foo self.x - other.x @@ -2873,7 +2873,7 @@ z.x fn arithmetic_assignment() { let script = " locals = {} -foo = |x| {x}.with_meta_map locals.foo_meta +foo = |x| {x}.set_meta locals.foo_meta locals.foo_meta = @+=: |y| self.x += y @-=: |y| self.x -= y @@ -3216,7 +3216,7 @@ x.skip(3).reversed().take(3).to_tuple() fn basic_access() { let script = " locals = {} -foo = |x| {x}.with_meta_map locals.foo_meta +foo = |x| {x}.set_meta locals.foo_meta locals.foo_meta = @meta get_x: || self.x a = foo 10 @@ -3229,7 +3229,7 @@ a.x + a.get_x() fn lookup_order() { let script = " locals = {} -foo = |x| {x, y: 100}.with_meta_map locals.foo_meta +foo = |x| {x, y: 100}.set_meta locals.foo_meta locals.foo_meta = @meta y: 0 a = foo 10 diff --git a/docs/core_lib/map.md b/docs/core_lib/map.md index bd7224a97..d4aa734fa 100644 --- a/docs/core_lib/map.md +++ b/docs/core_lib/map.md @@ -124,7 +124,7 @@ check! xyz - [`map.get`](#get) -## get_meta_map +## get_meta ```kototype |Map| -> Map @@ -139,7 +139,7 @@ my_map = data: 42 @type: 'My Map' -meta = map.get_meta_map my_map +meta = map.get_meta my_map print! map.keys(my_map).count() check! 1 @@ -152,7 +152,7 @@ check! My Map ### See also -- [`map.with_meta_map`](#with-meta-map) +- [`map.set_meta`](#set-meta) ## insert @@ -447,33 +447,27 @@ check! null - [`map.keys`](#keys) -## with_meta_map +## set_meta ```kototype |Map, Map| -> Map ``` -Returns a Map that contains the data from the first argument, and the Meta Map -from the second argument. +Sets the first argument's meta map to be an instance of the meta map from the +second argument. ### Example ```koto my_meta = - @type: 'My Meta' + @type: 'MyMeta' -my_data = - foo: 42 - -x = my_data.with_meta_map my_meta - -print! koto.type my_data -check! Map +x = {foo: 42}.set_meta my_meta print! koto.type x -check! My Meta +check! MyMeta ``` ### See also -- [`map.get_meta_map`](#get-meta-map) +- [`map.get_meta`](#get-meta) diff --git a/docs/language/meta_maps.md b/docs/language/meta_maps.md index 912fad138..e458d6c4c 100644 --- a/docs/language/meta_maps.md +++ b/docs/language/meta_maps.md @@ -280,20 +280,20 @@ check! ('data') ## Sharing Meta Maps -If you're creating lots of values, then it will likely be more efficient to create a single value with the meta logic, and then share it between values using [`Map.with_meta_map`](../../core/map/#with-meta-map). +If you're creating lots of values, then it will likely be more efficient to create a single map containing the meta logic, and then share it between instances using [`Map.set_meta`](../../core/map/#set-meta). ```koto -# Create an empty map for global values -globals = {} +# Create an empty map for global values +global = {} # Define a function that makes a Foo foo = |data| # Make a map that contains `data`, - # along with the meta map from foo_meta - {data}.with_meta_map globals.foo_meta + # and then assign a shared copy of the meta map from foo_meta + {data}.set_meta global.foo_meta # Define some meta behaviour in foo_meta -globals.foo_meta = +global.foo_meta = # Override the + operator @+: |other| foo self.data + other.data diff --git a/koto/tests/meta_maps.koto b/koto/tests/meta_maps.koto index b6922c6f8..b5039e031 100644 --- a/koto/tests/meta_maps.koto +++ b/koto/tests/meta_maps.koto @@ -3,7 +3,7 @@ globals = {} # foo acts as a constructor for the Foo type foo = |x| # Make a map that contains x, and return its data with the meta map from foo_meta - {x}.with_meta_map globals.foo_meta + {x}.set_meta globals.foo_meta # Declaring the overloaded operators once and then cloning the meta map into the foo # instance is more efficient than declaring them each time foo is called. @@ -182,11 +182,11 @@ globals.foo_meta = assert_eq f.hello, "Hello" assert_eq f.say_hello("you"), "Hello, you!" - @test get_meta_map: || + @test get_meta: || f = foo 42 - meta = map.get_meta_map f + meta = map.get_meta f - # get_meta_map returns a map with the argument's meta map, but no data + # get_meta returns a map with the argument's meta map, but no data assert_eq map.keys(meta).count(), 0 assert_eq meta.hello, "Hello" diff --git a/libs/color/src/lib.rs b/libs/color/src/lib.rs index a57012f01..455169c3d 100644 --- a/libs/color/src/lib.rs +++ b/libs/color/src/lib.rs @@ -52,7 +52,7 @@ pub fn make_module() -> KMap { unexpected => type_error_with_slice("a String", unexpected), }); - result.set_meta_map(Some(meta)); + result.set_meta_map(Some(meta.into())); result } From fbcba96a33fb3796cb72346e97088ebd98a9ee8d Mon Sep 17 00:00:00 2001 From: Ian Hobson Date: Fri, 26 Jan 2024 10:36:40 +0100 Subject: [PATCH 2/3] Re-enable some disabled checks in meta_maps.koto --- koto/tests/meta_maps.koto | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/koto/tests/meta_maps.koto b/koto/tests/meta_maps.koto index b5039e031..c34c65712 100644 --- a/koto/tests/meta_maps.koto +++ b/koto/tests/meta_maps.koto @@ -176,8 +176,10 @@ globals.foo_meta = @test named_meta_entries: || f = foo 99 - # assert_eq map.keys(f).to_list(), ["x"] - # assert_eq map.size(f), 1 + + # Map operations aren't inherited by the Foo meta map, so the map module has to be used directly + assert_eq map.keys(f).to_list(), ["x"] + assert_eq map.size(f), 1 assert_eq f.hello, "Hello" assert_eq f.say_hello("you"), "Hello, you!" From 8546cf0099a7815131b978014cf2989ed880e828 Mon Sep 17 00:00:00 2001 From: Ian Hobson Date: Fri, 26 Jan 2024 10:46:09 +0100 Subject: [PATCH 3/3] Make the CLI's -T option more user-friendly --- CHANGELOG.md | 4 +++- crates/cli/src/main.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d9b7fee..e5a09f9da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,11 +68,13 @@ The Koto project adheres to - The `rc` variant has slightly better performance at the cost of thread safety. -#### REPL +#### CLI - The REPL `config.koto` settings have all been moved into a `repl` sub-map. - e.g. `export { edit_mode: 'vi' }` is now `export { repl: { edit_mode: 'vi' }}` +- The `--import_tests`/`-T` CLI option will now run tests in the main script + along with any tests from imported modules. ### Removed diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 6e60959f9..df00e81ce 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -23,7 +23,7 @@ FLAGS: -i, --show_instructions Show compiled instructions annotated with source lines -b, --show_bytecode Show the script's compiled bytecode -t, --tests Run the script's tests before running the script - -T, --import_tests Run tests when importing modules + -T, --import_tests Run the script's tests, along with any tests in imported modules -c, --config PATH Config file to load when using the REPL -v, --version Prints version information -h, --help Prints help information @@ -129,7 +129,7 @@ fn main() -> Result<()> { } let koto_settings = KotoSettings { - run_tests: args.run_tests, + run_tests: args.run_tests || args.run_import_tests, run_import_tests: args.run_import_tests, ..Default::default() };