From 783553e4c197f13a4cd9e75a0b82a562f95cb7e4 Mon Sep 17 00:00:00 2001 From: Jianan Yao <31515200+jyao15@users.noreply.github.com> Date: Mon, 25 Jul 2022 08:41:39 -0700 Subject: [PATCH 001/169] add missing location line in error trace (#297) --- .../move-prover/boogie-backend/src/bytecode_translator.rs | 5 +++++ .../tests/sources/functional/aborts_if_with_code.exp | 3 +++ .../tests/sources/functional/global_invariants.exp | 2 ++ language/move-prover/tests/sources/functional/invariants.exp | 2 ++ .../move-prover/tests/sources/functional/is_txn_signer.exp | 1 + language/move-prover/tests/sources/functional/loops.exp | 5 +++++ .../tests/sources/functional/loops_with_memory_ops.exp | 5 +++++ .../tests/sources/functional/macro_verification.exp | 4 ++++ language/move-prover/tests/sources/functional/trace.exp | 2 +- 9 files changed, 28 insertions(+), 1 deletion(-) diff --git a/language/move-prover/boogie-backend/src/bytecode_translator.rs b/language/move-prover/boogie-backend/src/bytecode_translator.rs index ce93377000..1277a215b3 100644 --- a/language/move-prover/boogie-backend/src/bytecode_translator.rs +++ b/language/move-prover/boogie-backend/src/bytecode_translator.rs @@ -748,6 +748,11 @@ impl<'env> FunctionTranslator<'env> { *last_tracked_loc = None; } self.track_loc(last_tracked_loc, &loc); + if matches!(bytecode, Label(_, _)) { + // For labels, retrack the location after the label itself, so + // the information will not be missing if we jump to this label + *last_tracked_loc = None; + } // Helper function to get a a string for a local let str_local = |idx: usize| format!("$t{}", idx); diff --git a/language/move-prover/tests/sources/functional/aborts_if_with_code.exp b/language/move-prover/tests/sources/functional/aborts_if_with_code.exp index 4086da54df..a0a440d95b 100644 --- a/language/move-prover/tests/sources/functional/aborts_if_with_code.exp +++ b/language/move-prover/tests/sources/functional/aborts_if_with_code.exp @@ -14,6 +14,7 @@ error: abort code not covered by any of the `aborts_if` or `aborts_with` clauses = at tests/sources/functional/aborts_if_with_code.move:69: aborts_if_with_code_mixed_invalid = x = = at tests/sources/functional/aborts_if_with_code.move:70: aborts_if_with_code_mixed_invalid + = at tests/sources/functional/aborts_if_with_code.move:73: aborts_if_with_code_mixed_invalid = at tests/sources/functional/aborts_if_with_code.move:74: aborts_if_with_code_mixed_invalid = ABORTED @@ -31,6 +32,7 @@ error: abort code not covered by any of the `aborts_if` or `aborts_with` clauses = at tests/sources/functional/aborts_if_with_code.move:97: aborts_with_invalid = x = = at tests/sources/functional/aborts_if_with_code.move:98: aborts_with_invalid + = at tests/sources/functional/aborts_if_with_code.move:101: aborts_with_invalid = at tests/sources/functional/aborts_if_with_code.move:102: aborts_with_invalid = ABORTED @@ -50,6 +52,7 @@ error: abort code not covered by any of the `aborts_if` or `aborts_with` clauses = at tests/sources/functional/aborts_if_with_code.move:123: aborts_with_mixed_invalid = x = = at tests/sources/functional/aborts_if_with_code.move:124: aborts_with_mixed_invalid + = at tests/sources/functional/aborts_if_with_code.move:127: aborts_with_mixed_invalid = at tests/sources/functional/aborts_if_with_code.move:128: aborts_with_mixed_invalid = ABORTED diff --git a/language/move-prover/tests/sources/functional/global_invariants.exp b/language/move-prover/tests/sources/functional/global_invariants.exp index 976f3a7033..34ef8951fe 100644 --- a/language/move-prover/tests/sources/functional/global_invariants.exp +++ b/language/move-prover/tests/sources/functional/global_invariants.exp @@ -26,6 +26,7 @@ error: global memory invariant does not hold = at ../move-stdlib/sources/signer.move:13: address_of = result = = at ../move-stdlib/sources/signer.move:14: address_of + = at tests/sources/functional/global_invariants.move:65: remove_R_invalid = at ../move-stdlib/sources/signer.move:12: address_of = s = = at ../move-stdlib/sources/signer.move:13: address_of @@ -50,6 +51,7 @@ error: global memory invariant does not hold = at ../move-stdlib/sources/signer.move:13: address_of = result = = at ../move-stdlib/sources/signer.move:14: address_of + = at tests/sources/functional/global_invariants.move:56: remove_S_invalid = at ../move-stdlib/sources/signer.move:12: address_of = s = = at ../move-stdlib/sources/signer.move:13: address_of diff --git a/language/move-prover/tests/sources/functional/invariants.exp b/language/move-prover/tests/sources/functional/invariants.exp index 250c1e16c2..2c6590de0b 100644 --- a/language/move-prover/tests/sources/functional/invariants.exp +++ b/language/move-prover/tests/sources/functional/invariants.exp @@ -49,8 +49,10 @@ error: data invariant does not hold = at tests/sources/functional/invariants.move:143 = at tests/sources/functional/invariants.move:158: lifetime_invalid_S_branching = a = + = at tests/sources/functional/invariants.move:158: lifetime_invalid_S_branching = x_ref = = at tests/sources/functional/invariants.move:160: lifetime_invalid_S_branching + = at tests/sources/functional/invariants.move:163: lifetime_invalid_S_branching = at tests/sources/functional/invariants.move:143 = at tests/sources/functional/invariants.move:163: lifetime_invalid_S_branching = a = diff --git a/language/move-prover/tests/sources/functional/is_txn_signer.exp b/language/move-prover/tests/sources/functional/is_txn_signer.exp index 0b34fa194a..9d2fee976c 100644 --- a/language/move-prover/tests/sources/functional/is_txn_signer.exp +++ b/language/move-prover/tests/sources/functional/is_txn_signer.exp @@ -31,6 +31,7 @@ error: unknown assertion failed = at ../move-stdlib/sources/signer.move:13: address_of = result = = at ../move-stdlib/sources/signer.move:14: address_of + = at tests/sources/functional/is_txn_signer.move:31: f4_incorrect error: precondition does not hold at this call ┌─ tests/sources/functional/is_txn_signer.move:38:9 diff --git a/language/move-prover/tests/sources/functional/loops.exp b/language/move-prover/tests/sources/functional/loops.exp index b22201c36b..a5ff171d2d 100644 --- a/language/move-prover/tests/sources/functional/loops.exp +++ b/language/move-prover/tests/sources/functional/loops.exp @@ -80,6 +80,7 @@ error: induction case of the loop invariant does not hold = loop invariant holds at current state = at tests/sources/functional/loops.move:225: loop_invariant_induction_invalid = at tests/sources/functional/loops.move:221: loop_invariant_induction_invalid + = at tests/sources/functional/loops.move:227: loop_invariant_induction_invalid = x = = at tests/sources/functional/loops.move:223: loop_invariant_induction_invalid @@ -100,6 +101,7 @@ error: induction case of the loop invariant does not hold = y = = loop invariant holds at current state = at tests/sources/functional/loops.move:191: loop_with_two_back_edges_incorrect + = at tests/sources/functional/loops.move:192: loop_with_two_back_edges_incorrect = y = = at tests/sources/functional/loops.move:193: loop_with_two_back_edges_incorrect = at tests/sources/functional/loops.move:189: loop_with_two_back_edges_incorrect @@ -141,6 +143,7 @@ error: induction case of the loop invariant does not hold = y = = loop invariant holds at current state = at tests/sources/functional/loops.move:147: nested_loop_inner_invariant_incorrect + = at tests/sources/functional/loops.move:150: nested_loop_inner_invariant_incorrect = y = = at tests/sources/functional/loops.move:145: nested_loop_inner_invariant_incorrect @@ -163,5 +166,7 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops.move:122: nested_loop_outer_invariant_incorrect = enter loop, variable(s) y havocked and reassigned = y = + = at tests/sources/functional/loops.move:128: nested_loop_outer_invariant_incorrect + = at tests/sources/functional/loops.move:131: nested_loop_outer_invariant_incorrect = x = = at tests/sources/functional/loops.move:119: nested_loop_outer_invariant_incorrect diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp index 5ab43a180f..7a0a342456 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp @@ -43,6 +43,8 @@ error: unknown assertion failed = at tests/sources/functional/loops_with_memory_ops.move:74: nested_loop2 = enter loop, variable(s) y havocked and reassigned = y = + = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = = a = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 @@ -94,11 +96,14 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops_with_memory_ops.move:74: nested_loop2 = enter loop, variable(s) y havocked and reassigned = y = + = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = = a = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:89: nested_loop2 = a = = x = = at tests/sources/functional/loops_with_memory_ops.move:90: nested_loop2 diff --git a/language/move-prover/tests/sources/functional/macro_verification.exp b/language/move-prover/tests/sources/functional/macro_verification.exp index b4a1697d58..9ed2446485 100644 --- a/language/move-prover/tests/sources/functional/macro_verification.exp +++ b/language/move-prover/tests/sources/functional/macro_verification.exp @@ -36,6 +36,7 @@ error: post-condition does not hold = at tests/sources/functional/macro_verification.move:26: foreach = `invariant forall j in i..len(v): v[j] == old(v)[j];` = = at tests/sources/functional/macro_verification.move:17: foreach + = at tests/sources/functional/macro_verification.move:27: foreach = v = = at tests/sources/functional/macro_verification.move:30: foreach (spec) = `ensures len(v) == len(old(v));` = @@ -76,6 +77,7 @@ error: post-condition does not hold = at tests/sources/functional/macro_verification.move:50: reduce = `invariant sum == spec_sum(v, i);` = = at tests/sources/functional/macro_verification.move:43: reduce + = at tests/sources/functional/macro_verification.move:52: reduce = result = = at tests/sources/functional/macro_verification.move:55: reduce (spec) = `ensures result == spec_sum(v, len(v));` = @@ -123,7 +125,9 @@ error: post-condition does not hold = at tests/sources/functional/macro_verification.move:49: reduce = at tests/sources/functional/macro_verification.move:50: reduce = at tests/sources/functional/macro_verification.move:43: reduce + = at tests/sources/functional/macro_verification.move:52: reduce = result = + = at tests/sources/functional/macro_verification.move:53: reduce = result = = at tests/sources/functional/macro_verification.move:73: reduce_test = at tests/sources/functional/macro_verification.move:75: reduce_test (spec) diff --git a/language/move-prover/tests/sources/functional/trace.exp b/language/move-prover/tests/sources/functional/trace.exp index ea08b2a3c9..8e1a738de5 100644 --- a/language/move-prover/tests/sources/functional/trace.exp +++ b/language/move-prover/tests/sources/functional/trace.exp @@ -45,7 +45,7 @@ error: post-condition does not hold │ = Related Global Memory: = Resource name: TestTracing_R - = Values: {Address(26500): , Default: empty} + = Values: {Address(18467): , Default: empty} = Related Bindings: = addr = = exists(addr) = From f04e6aff16edf1b3bb32dcce4beca275e04c68e0 Mon Sep 17 00:00:00 2001 From: Ville Sundell Date: Mon, 25 Jul 2022 18:42:57 +0300 Subject: [PATCH 002/169] [chore] Updated Rust packages to pass the Cargo audit (#301) Updated Rust packages in order to pass the Cargo audit. Time is not updated. Instead the security advisory RUSTSEC-2020-0071 should be ignored, since it does not affect Chrono, our only dependency using it. Took cue from Diem's commit: f416e383e ("fix rustsec vulnerabilities", 2022-06-22). --- .github/workflows/daily.yml | 3 +- Cargo.lock | 221 +++++++++++++++--- devtools/x/Cargo.toml | 2 +- language/move-compiler/Cargo.toml | 2 +- language/move-core/types/Cargo.toml | 2 +- language/move-model/Cargo.toml | 2 +- language/move-prover/Cargo.toml | 2 +- .../move-prover/boogie-backend/Cargo.toml | 6 +- language/move-prover/move-docgen/Cargo.toml | 2 +- language/move-prover/test-utils/Cargo.toml | 2 +- .../testing-infra/test-generation/Cargo.toml | 2 +- .../tools/move-bytecode-viewer/Cargo.toml | 2 +- language/tools/move-unit-test/Cargo.toml | 2 +- 13 files changed, 209 insertions(+), 41 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 5901e076e9..75a84815e9 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -20,8 +20,9 @@ jobs: # List of ignored RUSTSEC # 1. RUSTSEC-2021-0073 - Not impacted. # 2. RUSTSEC-2021-0072 - Not impacted. + # 3. RUSTSEC-2020-0071 - Not impacted (chronotope/chrono#578). run: | - cargo audit --color never --ignore RUSTSEC-2021-0073 --ignore RUSTSEC-2021-0072 > $AUDIT_SUMMARY_FILE + cargo audit --color never --ignore RUSTSEC-2021-0073 --ignore RUSTSEC-2021-0072 --ignore RUSTSEC-2020-0071 > $AUDIT_SUMMARY_FILE - name: set issue body content if: ${{ failure() }} env: diff --git a/Cargo.lock b/Cargo.lock index 8a1b863084..2d837b4ff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,12 +508,24 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2554a3155fec064362507487171dcc4edc3df60cb10f3a1fb10ed8094822b120" +checksum = "58549f1842da3080ce63002102d5bc954c7bc843d4f47818e642abdc36253552" dependencies = [ "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" +dependencies = [ "parse-zoneinfo", + "phf", + "phf_codegen", ] [[package]] @@ -802,7 +814,7 @@ dependencies = [ "bitflags", "crossterm_winapi 0.8.0", "libc", - "mio", + "mio 0.7.13", "parking_lot 0.11.1", "signal-hook", "signal-hook-mio", @@ -818,7 +830,7 @@ dependencies = [ "bitflags", "crossterm_winapi 0.9.0", "libc", - "mio", + "mio 0.7.13", "parking_lot 0.11.1", "signal-hook", "signal-hook-mio", @@ -2099,9 +2111,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.112" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" @@ -2120,9 +2132,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -2211,6 +2223,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + [[package]] name = "miow" version = "0.3.7" @@ -3495,10 +3519,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", - "lock_api 0.4.4", + "lock_api 0.4.6", "parking_lot_core 0.8.3", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api 0.4.6", + "parking_lot_core 0.9.3", +] + [[package]] name = "parking_lot_core" version = "0.7.2" @@ -3527,6 +3561,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.10", + "smallvec", + "windows-sys", +] + [[package]] name = "parse-zoneinfo" version = "0.3.0" @@ -3620,6 +3667,45 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand 0.8.4", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", + "uncased", +] + [[package]] name = "pin-project-lite" version = "0.2.7" @@ -4602,7 +4688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" dependencies = [ "libc", - "mio", + "mio 0.7.13", "signal-hook", ] @@ -4632,6 +4718,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "sized-chunks" version = "0.6.5" @@ -4675,6 +4767,16 @@ dependencies = [ "structopt 0.3.25", ] +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spec-flatten" version = "0.1.0" @@ -4857,9 +4959,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.7.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2617ab2fb1de8587a988a761692e59895438bebf404725d4f2123251f60bf23e" +checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" dependencies = [ "chrono", "chrono-tz", @@ -4959,9 +5061,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ "once_cell", ] @@ -5022,29 +5124,29 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.9.0" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" dependencies = [ - "autocfg", "bytes", "libc", "memchr", - "mio", + "mio 0.8.4", "num_cpus", "once_cell", - "parking_lot 0.11.1", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", "winapi", ] [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2 1.0.28", "quote 1.0.9", @@ -5086,11 +5188,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static 1.4.0", + "once_cell", + "valuable", ] [[package]] @@ -5106,13 +5209,13 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.3" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ "ansi_term 0.12.1", - "lazy_static 1.4.0", "matchers", + "once_cell", "regex", "sharded-slab", "smallvec", @@ -5199,6 +5302,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check", +] + [[package]] name = "unic-char-property" version = "0.9.0" @@ -5326,6 +5438,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "variant_count" version = "1.1.0" @@ -5401,6 +5519,12 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.71" @@ -5502,6 +5626,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "wyz" version = "0.2.0" diff --git a/devtools/x/Cargo.toml b/devtools/x/Cargo.toml index 2d9c9498ea..59596f3610 100644 --- a/devtools/x/Cargo.toml +++ b/devtools/x/Cargo.toml @@ -23,7 +23,7 @@ env_logger = "0.8.3" log = "0.4.14" chrono = "0.4.19" globset = "0.4.6" -regex = "1.4.3" +regex = "1.5.5" rayon = "1.5.0" nextest-config = { git = "https://github.com/diem/diem-devtools", rev = "f99a204e3d3f8e503d51d7df42e55c8282b59154" } nextest-runner = { git = "https://github.com/diem/diem-devtools", rev = "f99a204e3d3f8e503d51d7df42e55c8282b59154" } diff --git a/language/move-compiler/Cargo.toml b/language/move-compiler/Cargo.toml index 0eb2706c1f..38cffc1e0b 100644 --- a/language/move-compiler/Cargo.toml +++ b/language/move-compiler/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" anyhow = "1.0.52" codespan-reporting = "0.11.1" hex = "0.4.3" -regex = "1.4.3" +regex = "1.5.5" clap = { version = "3.1.8", features = ["derive"] } difference = "2.0.0" petgraph = "0.5.1" diff --git a/language/move-core/types/Cargo.toml b/language/move-core/types/Cargo.toml index 49815fb706..c5f48be883 100644 --- a/language/move-core/types/Cargo.toml +++ b/language/move-core/types/Cargo.toml @@ -24,7 +24,7 @@ serde_bytes = "0.11.5" [dev-dependencies] proptest = "1.0.0" proptest-derive = "0.3.0" -regex = "1.4.3" +regex = "1.5.5" serde_json = "1.0.64" [features] diff --git a/language/move-model/Cargo.toml b/language/move-model/Cargo.toml index 09aeb0d4dc..ef99df1a2b 100644 --- a/language/move-model/Cargo.toml +++ b/language/move-model/Cargo.toml @@ -26,7 +26,7 @@ itertools = "0.10.0" log = "0.4.14" num = "0.4.0" once_cell = "1.7.2" -regex = "1.4.3" +regex = "1.5.5" anyhow = "1.0.52" serde = { version = "1.0.124", features = ["derive"] } diff --git a/language/move-prover/Cargo.toml b/language/move-prover/Cargo.toml index d527848363..fb7369fbdc 100644 --- a/language/move-prover/Cargo.toml +++ b/language/move-prover/Cargo.toml @@ -38,7 +38,7 @@ serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" simplelog = "0.9.0" once_cell = "1.7.2" -tokio = { version = "1.8.1", features = ["full"] } +tokio = { version = "1.18.2", features = ["full"] } toml = "0.5.8" [dev-dependencies] diff --git a/language/move-prover/boogie-backend/Cargo.toml b/language/move-prover/boogie-backend/Cargo.toml index 96b571961e..2a0256eb23 100644 --- a/language/move-prover/boogie-backend/Cargo.toml +++ b/language/move-prover/boogie-backend/Cargo.toml @@ -22,10 +22,10 @@ serde_json = "1.0.64" anyhow = "1.0.52" once_cell = "1.7.2" pretty = "0.10.0" -regex = "1.4.3" +regex = "1.5.5" rand = "0.8.3" futures = "0.3.12" -tera = "1.7.1" -tokio = { version = "1.8.1", features = ["full"] } +tera = "1.16.0" +tokio = { version = "1.18.2", features = ["full"] } codespan = "0.11.1" codespan-reporting = "0.11.1" diff --git a/language/move-prover/move-docgen/Cargo.toml b/language/move-prover/move-docgen/Cargo.toml index 91a71f4ca2..21084f1aeb 100644 --- a/language/move-prover/move-docgen/Cargo.toml +++ b/language/move-prover/move-docgen/Cargo.toml @@ -17,7 +17,7 @@ codespan-reporting = "0.11.1" itertools = "0.10.0" log = "0.4.14" num = "0.4.0" -regex = "1.4.3" +regex = "1.5.5" anyhow = "1.0.52" serde = { version = "1.0.124", features = ["derive"] } once_cell = "1.7.2" diff --git a/language/move-prover/test-utils/Cargo.toml b/language/move-prover/test-utils/Cargo.toml index fc5ff22f1f..d632191aee 100644 --- a/language/move-prover/test-utils/Cargo.toml +++ b/language/move-prover/test-utils/Cargo.toml @@ -9,5 +9,5 @@ license = "Apache-2.0" [dependencies] prettydiff = "0.4.0" anyhow = "1.0.52" -regex = "1.4.3" +regex = "1.5.5" move-command-line-common = { path = "../../move-command-line-common" } diff --git a/language/testing-infra/test-generation/Cargo.toml b/language/testing-infra/test-generation/Cargo.toml index 83ac8f35ff..6834936146 100644 --- a/language/testing-infra/test-generation/Cargo.toml +++ b/language/testing-infra/test-generation/Cargo.toml @@ -18,7 +18,7 @@ hex = "0.4.3" getrandom = "0.2.2" crossbeam-channel = "0.5.0" tracing = "0.1.26" -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } +tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } once_cell = "1.7.2" move-bytecode-verifier = { path = "../../move-bytecode-verifier" } diff --git a/language/tools/move-bytecode-viewer/Cargo.toml b/language/tools/move-bytecode-viewer/Cargo.toml index 82e2ab8d68..9dad79f75e 100644 --- a/language/tools/move-bytecode-viewer/Cargo.toml +++ b/language/tools/move-bytecode-viewer/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" [dependencies] clap = { version = "3.1.8", features = ["derive"] } anyhow = "1.0.52" -regex = "1.1.9" +regex = "1.5.5" tui = "0.17.0" crossterm = "0.21" diff --git a/language/tools/move-unit-test/Cargo.toml b/language/tools/move-unit-test/Cargo.toml index 8b4a964dc1..8cfcf0d34b 100644 --- a/language/tools/move-unit-test/Cargo.toml +++ b/language/tools/move-unit-test/Cargo.toml @@ -16,7 +16,7 @@ clap = { version = "3.1.8", features = ["derive"] } codespan-reporting = "0.11.1" colored = "2.0.0" rayon = "1.5.0" -regex = "1.1.9" +regex = "1.5.5" once_cell = "1.7.2" itertools = "0.10.1" From 1cd2d8ae22bf77ecbec3e88fe5a66070dcb96d3c Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Mon, 25 Jul 2022 11:53:53 -0400 Subject: [PATCH 003/169] [move-prover] fix hyper-edge constructor in borrow analysis (#298) * [move-prover] fix hyper-edge constructor in borrow analysis This commit fixes issue #270 where the edge ordering are reversed in a hyper-edge when that hyper-edge is inlined to construct a borrow graph. In Move Prover, hyper-edges are used to summarize the borrow-relation between function arguments and function return values: In the example in #270, given ```move fun inner(has_vector: &mut HasVector): &mut HasAnotherVector { vector::borrow_mut(&mut has_vector.v, 7) } ``` The `inner` function will yield a hyper-edge: ``` return_ref --borrows_from--> { arg: has_vector, edge: Hyper(.v/[]) } ``` Now, this hyper-edge will be further used to derive the borrow-relation for the `mid` function: ``` fun mid(has_vector: &mut HasVector): &mut HasAnotherVector { inner(has_vector) } ``` The expected summary for `mid` is ``` return_ref --borrows_from--> { arg: has_vector, edge: Hyper(.v/[]) } ``` However, due to the bug, the summary becomes: ``` return_ref --borrows_from--> { arg: has_vector, edge: Hyper([]/.v) } ^^^^^ // reversed ``` which causes the crash found in #270. This commit fixes this bug. In summary, the fix is: when constructing hyper-edges, reverse the edges first before flattening all the edges. --- .../bytecode/src/borrow_analysis.rs | 10 ++++++-- .../bytecode/tests/borrow/function_call.exp | 24 +++++++++---------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/language/move-prover/bytecode/src/borrow_analysis.rs b/language/move-prover/bytecode/src/borrow_analysis.rs index 88d36a2f30..0024322954 100644 --- a/language/move-prover/bytecode/src/borrow_analysis.rs +++ b/language/move-prover/bytecode/src/borrow_analysis.rs @@ -260,7 +260,7 @@ impl BorrowInfo { ) { for (dest, edge) in outgoing.iter() { let mut path = prefix.to_owned(); - path.extend(edge.flatten().into_iter().cloned()); + path.push(edge.clone()); if let Some(succs) = ret_info.borrows_from.get(dest) { self.construct_hyper_edges(leaf, ret_info, path, succs); } else { @@ -269,7 +269,13 @@ impl BorrowInfo { path.pop().unwrap() } else { path.reverse(); - BorrowEdge::Hyper(path) + let flattened = path + .iter() + .map(|e| e.flatten().into_iter()) + .flatten() + .cloned() + .collect(); + BorrowEdge::Hyper(flattened) }; self.borrowed_by .entry(dest.clone()) diff --git a/language/move-prover/bytecode/tests/borrow/function_call.exp b/language/move-prover/bytecode/tests/borrow/function_call.exp index 5992a663df..fbafcf7783 100644 --- a/language/move-prover/bytecode/tests/borrow/function_call.exp +++ b/language/move-prover/bytecode/tests/borrow/function_call.exp @@ -262,27 +262,27 @@ fun MultiLayerCalling::outer($t0|has_vector: &mut MultiLayerCalling::HasVector) 0: $t2 := MultiLayerCalling::mid($t0) # live_nodes: Reference($t0), Reference($t2) # moved_nodes: Reference($t0) - # borrowed_by: Reference($t0) -> {([]/.v (vector), Reference($t2))} - # borrows_from: Reference($t2) -> {([]/.v (vector), Reference($t0))} + # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))} + # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))} 1: $t3 := borrow_field.v($t2) # live_nodes: Reference($t0), Reference($t3) # moved_nodes: Reference($t0) - # borrowed_by: Reference($t0) -> {([]/.v (vector), Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} - # borrows_from: Reference($t2) -> {([]/.v (vector), Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} + # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} + # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 2: $t4 := 42 # live_nodes: Reference($t0), Reference($t3) # moved_nodes: Reference($t0) - # borrowed_by: Reference($t0) -> {([]/.v (vector), Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} - # borrows_from: Reference($t2) -> {([]/.v (vector), Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} + # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} + # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 3: vector::push_back($t3, $t4) # live_nodes: Reference($t0) # moved_nodes: Reference($t0) - # borrowed_by: Reference($t0) -> {([]/.v (vector), Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} - # borrows_from: Reference($t2) -> {([]/.v (vector), Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} + # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} + # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 4: trace_local[has_vector]($t0) # moved_nodes: Reference($t0) - # borrowed_by: Reference($t0) -> {([]/.v (vector), Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} - # borrows_from: Reference($t2) -> {([]/.v (vector), Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} + # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} + # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 5: return () } @@ -299,5 +299,5 @@ borrowed_by: Reference($t0) -> {(.v (vector borrows_from: Return(0) -> {(.v (vector)/[], Reference($t0))} fun MultiLayerCalling::mid[baseline] -borrowed_by: Reference($t0) -> {([]/.v (vector), Return(0))} -borrows_from: Return(0) -> {([]/.v (vector), Reference($t0))} +borrowed_by: Reference($t0) -> {(.v (vector)/[], Return(0))} +borrows_from: Return(0) -> {(.v (vector)/[], Reference($t0))} From f0e4ed0ed2fe4dcfde499404fa7dcfe90652e84e Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Mon, 25 Jul 2022 12:51:46 -0400 Subject: [PATCH 004/169] [move-prover] write-back following the whole ancestor tree (#302) * [move-prover] write-back following the whole ancestor tree The current memory model in Move Prover has a flaw in writing back dying references, as identified in issue #299. The gist of the flaw is this: we can only write-back a reference on code paths where it is guaranteed to be defined. Otherwise in the prover's point of view, the write-back may cause arbitrary value to be written back to the parent `Mutation` value and cause unexpected verification failures. As a side note, this is also visible in the concrete executor of the spec + move (i.e., the stackless VM). The solution, as implemented in this commit, is to ravamp the way write-backs are done. In summary, the solution is to write-back the dying references according to DFS paths instead of BFS layers. Taking the example in #299: The borrow graph looks like this: ``` --borrows_from--> t7 --borrows_from--> Global(t1) t3 --| --borrows_from--> t8 --borrows_from--> Global(t2) ``` And the old approach is to write-back according to BFS layers, i.e., t3, then t7 and t8, which yields the following psudo-code. ``` if IsParent[t7](t3) { WriteBack[t7](t3); } if IsParent[t8](t3) { WriteBack[t8](t3); } // both t7 and t8 are not always defined when code reaches here WriteBack[Global](t7); WriteBack[Global](t8); ``` The correct behavior should be DFS paths, i.e.: ``` if IsParent[t7](t3) { WriteBack[t7](t3); // t7 is guaranteed to be defined when code reaches here WriteBack[Global](t7); } if IsParent[t8](t3) { WriteBack[t8](t3); // similarly, t8 is guaranteed to be defined in this block WriteBack[Global](t8); } ``` --- .../bytecode/src/borrow_analysis.rs | 131 +++++++++-------- .../bytecode/src/memory_instrumentation.rs | 132 +++++++++++++----- .../functional/conditional_write_back.move | 99 +++++++++++++ .../tests/sources/functional/invariants.exp | 3 +- 4 files changed, 265 insertions(+), 100 deletions(-) create mode 100644 language/move-prover/tests/sources/functional/conditional_write_back.move diff --git a/language/move-prover/bytecode/src/borrow_analysis.rs b/language/move-prover/bytecode/src/borrow_analysis.rs index 0024322954..d5f1bc9b82 100644 --- a/language/move-prover/bytecode/src/borrow_analysis.rs +++ b/language/move-prover/bytecode/src/borrow_analysis.rs @@ -21,11 +21,7 @@ use move_model::{ ty::Type, well_known::{TABLE_BORROW_MUT, VECTOR_BORROW_MUT}, }; -use std::{ - borrow::BorrowMut, - collections::{BTreeMap, BTreeSet}, - fmt, -}; +use std::{borrow::BorrowMut, collections::BTreeMap, fmt}; #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Default)] pub struct BorrowInfo { @@ -44,44 +40,29 @@ pub struct BorrowInfo { borrows_from: MapDomain>, } +/// Represents a write-back from a source node to a destination node with the associated edge +#[derive(Debug, Clone)] +pub struct WriteBackAction { + pub src: BorrowNode, + pub dst: BorrowNode, + pub edge: BorrowEdge, +} + impl BorrowInfo { /// Gets the children of this node. - pub fn get_children(&self, node: &BorrowNode) -> Vec<&BorrowNode> { + fn get_children(&self, node: &BorrowNode) -> Vec<&BorrowNode> { self.borrowed_by .get(node) .map(|s| s.iter().map(|(n, _)| n).collect_vec()) - .unwrap_or_else(Vec::new) + .unwrap_or_default() } - /// Gets the parents of this node. - pub fn get_parents(&self, node: &BorrowNode) -> Vec<&BorrowNode> { + /// Gets the parents (together with the edges) of this node. + fn get_incoming(&self, node: &BorrowNode) -> Vec<(&BorrowNode, &BorrowEdge)> { self.borrows_from .get(node) - .map(|s| s.iter().map(|(n, _)| n).collect_vec()) - .unwrap_or_else(Vec::new) - } - - /// Gets incoming edges (together with sources) of this node. - pub fn get_incoming(&self, node: &BorrowNode) -> SetDomain<(BorrowNode, BorrowEdge)> { - self.borrows_from.get(node).cloned().unwrap_or_default() - } - - /// Returns true if this node is conditional, that is, it borrows from multiple parents, - /// or has a transient child which is conditional. - pub fn is_conditional(&self, node: &BorrowNode) -> bool { - if let Some(parents) = self.borrows_from.get(node) { - // If there are more than one parent for this node, it is - // conditional. - if parents.len() > 1 { - return true; - } - } - if let Some(childs) = self.borrowed_by.get(node) { - // Otherwise we look for a child that is conditional. - childs.iter().any(|(c, _)| self.is_conditional(c)) - } else { - false - } + .map(|s| s.iter().map(|(n, e)| (n, e)).collect_vec()) + .unwrap_or_default() } /// Checks whether a node is in use. A node is used if it is in the live_nodes set @@ -96,45 +77,75 @@ impl BorrowInfo { } } - /// Checks whether this is a moved node. - pub fn is_moved(&self, node: &BorrowNode) -> bool { - self.moved_nodes.contains(node) - } - /// Returns nodes which are dying from this to the next state. This includes those which /// are directly dying plus those from which they borrow. Returns nodes in child-first order. - pub fn dying_nodes(&self, next: &BorrowInfo) -> Vec { - let mut visited = BTreeSet::new(); + pub fn dying_nodes(&self, next: &BorrowInfo) -> Vec<(BorrowNode, Vec>)> { let mut result = vec![]; for dying in self.live_nodes.difference(&next.live_nodes) { - // Collect ancestors, but exclude those which are still in use. Some nodes may be - // dying regards direct usage in instructions, but they may still be ancestors of - // living nodes (this is what `is_in_use` checks for). - if !next.is_in_use(dying) { - self.collect_ancestors(&mut visited, &mut result, dying, &|n| !next.is_in_use(n)); + if next.is_in_use(dying) { + continue; } + + // Collect ancestors trees until reaching an ancestor that is still in use. + let dying_trees = self.collect_dying_ancestor_trees(dying, next); + result.push((dying.clone(), dying_trees)); } result } - /// Collects this node and ancestors, inserting them in child-first order into the - /// given vector. Ancestors are only added if they fulfill the predicate. - fn collect_ancestors

( + /// Start from this node and follow-up the borrow chain until reaching a live/in-use ancestor. + /// Collect possible paths (from this node to a live ancestor) and return them in the DFS order. + fn collect_dying_ancestor_trees( &self, - visited: &mut BTreeSet, - order: &mut Vec, node: &BorrowNode, - cond: &P, - ) where - P: Fn(&BorrowNode) -> bool, - { - if visited.insert(node.clone()) { - order.push(node.clone()); - for parent in self.get_parents(node) { - if cond(parent) { - self.collect_ancestors(visited, order, parent, cond); + next: &BorrowInfo, + ) -> Vec> { + let mut trees = vec![]; + self.collect_dying_ancestor_trees_recursive(node, next, vec![], &mut trees); + trees + } + + fn collect_dying_ancestor_trees_recursive( + &self, + node: &BorrowNode, + next: &BorrowInfo, + order: Vec, + trees: &mut Vec>, + ) { + match node { + BorrowNode::LocalRoot(..) | BorrowNode::GlobalRoot(..) => { + trees.push(order); + } + BorrowNode::Reference(..) => { + if next.is_in_use(node) { + // stop at a live reference + trees.push(order); + } else { + let incoming = self.get_incoming(node); + if incoming.is_empty() { + // when the borrow reference node has no incoming edges, it means that this + // reference is a function argument. + trees.push(order); + } else { + // when there are incoming edges, this borrow occurs within the body + // of this function and this node need to be further traced upwards. + for (parent, edge) in incoming { + let mut appended = order.clone(); + appended.push(WriteBackAction { + src: node.clone(), + dst: parent.clone(), + edge: edge.clone(), + }); + self.collect_dying_ancestor_trees_recursive( + parent, next, appended, trees, + ); + } + } } } + BorrowNode::ReturnPlaceholder(..) => { + unreachable!("placeholder node type is not expected here"); + } } } diff --git a/language/move-prover/bytecode/src/memory_instrumentation.rs b/language/move-prover/bytecode/src/memory_instrumentation.rs index b58ff00949..da588e0842 100644 --- a/language/move-prover/bytecode/src/memory_instrumentation.rs +++ b/language/move-prover/bytecode/src/memory_instrumentation.rs @@ -107,6 +107,8 @@ impl<'a> Instrumenter<'a> { } fn memory_instrumentation(&mut self, code_offset: CodeOffset, bytecode: &Bytecode) { + let param_count = self.builder.get_target().get_parameter_count(); + let borrow_annotation_at = self .borrow_annotation .get_borrow_info_at(code_offset) @@ -138,59 +140,111 @@ impl<'a> Instrumenter<'a> { // Generate PackRef for nodes which go out of scope, as well as WriteBack. let attr_id = bytecode.get_attr_id(); - for node in before.dying_nodes(after) { - if let BorrowNode::Reference(idx) = &node { - // Generate write_back for this reference. - let is_conditional = before.is_conditional(&node); - for (parent, edge) in before.get_incoming(&node) { - self.builder.set_loc_from_attr(attr_id); - let skip_label_opt = match parent { - BorrowNode::Reference(..) if is_conditional => { - let temp = self.builder.new_temp(BOOL_TYPE.clone()); - self.builder.emit_with(|id| { - Bytecode::Call( - id, - vec![temp], - Operation::IsParent(parent.clone(), edge.clone()), - vec![*idx], - None, - ) - }); - let update_label = self.builder.new_label(); - let skip_label = self.builder.new_label(); - self.builder.emit_with(|id| { - Bytecode::Branch(id, update_label, skip_label, temp) - }); - self.builder - .emit_with(|id| Bytecode::Label(id, update_label)); - Some(skip_label) - } - _ => None, + for (node, ancestors) in before.dying_nodes(after) { + // we only care about references that occurs in the function body + let node_idx = match node { + BorrowNode::LocalRoot(..) | BorrowNode::GlobalRoot(..) => { + continue; + } + BorrowNode::Reference(idx) => { + if idx < param_count { + continue; + } + idx + } + BorrowNode::ReturnPlaceholder(..) => { + unreachable!("Unexpected placeholder borrow node"); + } + }; + + // Generate write_back for this reference. + let is_conditional = ancestors.len() > 1; + for tree in ancestors { + let parent = match tree.first() { + Some(action) => { + // the src node of the first action must be the node itself + assert!(matches!( + action.src, + BorrowNode::Reference(idx) if idx == node_idx + )); + action + } + None => { + unreachable!( + "The ancestor tree should contain at least one write-back action" + ); + } + }; + + // decide on whether we need IsParent checks + self.builder.set_loc_from_attr(attr_id); + let skip_label_opt = match parent.dst { + BorrowNode::Reference(..) if is_conditional => { + let temp = self.builder.new_temp(BOOL_TYPE.clone()); + self.builder.emit_with(|id| { + Bytecode::Call( + id, + vec![temp], + Operation::IsParent(parent.dst.clone(), parent.edge.clone()), + vec![node_idx], + None, + ) + }); + let update_label = self.builder.new_label(); + let skip_label = self.builder.new_label(); + self.builder + .emit_with(|id| Bytecode::Branch(id, update_label, skip_label, temp)); + self.builder + .emit_with(|id| Bytecode::Label(id, update_label)); + Some(skip_label) + } + _ => None, + }; + + // issue a chain of write-back actions + for action in &tree { + // obtain the source of the write-back + let src_idx = match &action.src { + BorrowNode::Reference(idx) => *idx, + _ => unreachable!( + "The source of a write-back action must always be a reference" + ), }; + + // decide if we need a pack-ref (i.e., data structure invariant checking) if matches!( - parent, + action.dst, BorrowNode::LocalRoot(..) | BorrowNode::GlobalRoot(..) ) { // On write-back to a root, "pack" the reference i.e. validate all its // invariants. - let ty = &self.builder.get_target().get_local_type(*idx).to_owned(); + let ty = &self.builder.get_target().get_local_type(src_idx).to_owned(); if self.is_pack_ref_ty(ty) { self.builder.emit_with(|id| { - Bytecode::Call(id, vec![], Operation::PackRefDeep, vec![*idx], None) + Bytecode::Call( + id, + vec![], + Operation::PackRefDeep, + vec![src_idx], + None, + ) }); } } + + // emit the write-back self.builder.emit_with(|id| { Bytecode::Call( id, vec![], - Operation::WriteBack(parent.clone(), edge), - vec![*idx], + Operation::WriteBack(action.dst.clone(), action.edge.clone()), + vec![src_idx], None, ) }); - // Add a trace for written back value if it's a user variable. - match parent { + + // add a trace for written back value if it's a user variable. + match action.dst { BorrowNode::LocalRoot(temp) | BorrowNode::Reference(temp) => { if temp < self.builder.fun_env.get_local_count() { self.builder.emit_with(|id| { @@ -206,9 +260,11 @@ impl<'a> Instrumenter<'a> { } _ => {} } - if let Some(label) = skip_label_opt { - self.builder.emit_with(|id| Bytecode::Label(id, label)); - } + } + + // continued from IsParent check + if let Some(label) = skip_label_opt { + self.builder.emit_with(|id| Bytecode::Label(id, label)); } } } diff --git a/language/move-prover/tests/sources/functional/conditional_write_back.move b/language/move-prover/tests/sources/functional/conditional_write_back.move new file mode 100644 index 0000000000..fc3f958443 --- /dev/null +++ b/language/move-prover/tests/sources/functional/conditional_write_back.move @@ -0,0 +1,99 @@ +module 0x42::Test { + struct S { + x: u64, + y: u64, + } + + struct T has key { + x: u64, + } + + struct R has key { + x: u64, + } + + public fun diff_field(cond: bool): S { + let s = S { x: 0, y: 0 }; + + let f = if (cond) { + &mut s.x + } else { + &mut s.y + }; + *f = 1; + + s + } + spec diff_field { + ensures cond ==> (result.x == 1 && result.y == 0); + ensures (!cond) ==> (result.x == 0 && result.y == 1); + } + + public fun diff_address(cond: bool, a1: address, a2: address) acquires T { + let x = if (cond) { + let t1 = borrow_global_mut(a1); + &mut t1.x + } else { + let t2 = borrow_global_mut(a2); + &mut t2.x + }; + *x = 0; + } + spec diff_address { + aborts_if cond && !exists(a1); + aborts_if !cond && !exists(a2); + ensures if (cond) global(a1).x == 0 else global(a2).x == 0; + } + + public fun diff_location(cond: bool, a: address, l: &mut T) acquires T { + let x = if (cond) { + let t1 = borrow_global_mut(a); + &mut t1.x + } else { + let t2 = l; + &mut t2.x + }; + *x = 0; + } + spec diff_location { + aborts_if cond && !exists(a); + ensures if (cond) global(a).x == 0 else l.x == 0; + } + + public fun diff_resource(cond: bool, a: address) acquires T, R { + let x = if (cond) { + let t1 = borrow_global_mut(a); + &mut t1.x + } else { + let t2 = borrow_global_mut(a); + &mut t2.x + }; + *x = 0; + } + spec diff_resource { + aborts_if cond && !exists(a); + aborts_if !cond && !exists(a); + ensures if (cond) global(a).x == 0 else global(a).x == 0; + } + + struct V has key { + x: u64, + y: T, + } + + public fun diff_resource_generic(cond: bool, a: address) acquires V { + let x = if (cond) { + let t1 = borrow_global_mut>(a); + &mut t1.x + } else { + let t2 = borrow_global_mut>(a); + &mut t2.x + }; + *x = 0; + } + spec diff_resource_generic { + aborts_if cond && !exists>(a); + aborts_if !cond && !exists>(a); + ensures if (cond) global>(a).x == 0 else global>(a).x == 0; + } +} diff --git a/language/move-prover/tests/sources/functional/invariants.exp b/language/move-prover/tests/sources/functional/invariants.exp index 2c6590de0b..7bd3cbe7b3 100644 --- a/language/move-prover/tests/sources/functional/invariants.exp +++ b/language/move-prover/tests/sources/functional/invariants.exp @@ -53,7 +53,6 @@ error: data invariant does not hold = x_ref = = at tests/sources/functional/invariants.move:160: lifetime_invalid_S_branching = at tests/sources/functional/invariants.move:163: lifetime_invalid_S_branching - = at tests/sources/functional/invariants.move:143 + = at :1 = at tests/sources/functional/invariants.move:163: lifetime_invalid_S_branching - = a = = at tests/sources/functional/invariants.move:150 From 57fa2e5c417ddd35f98dc4e4cf7beb892171c346 Mon Sep 17 00:00:00 2001 From: Adam Welc Date: Mon, 25 Jul 2022 10:40:20 -0700 Subject: [PATCH 005/169] [Move analyzer] Increased stack size of initial symbolication run (#306) --- .../move-analyzer/src/bin/move-analyzer.rs | 27 +++++++++++++------ language/move-analyzer/src/symbols.rs | 5 +++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/language/move-analyzer/src/bin/move-analyzer.rs b/language/move-analyzer/src/bin/move-analyzer.rs index 090076ac69..779c8c4c6e 100644 --- a/language/move-analyzer/src/bin/move-analyzer.rs +++ b/language/move-analyzer/src/bin/move-analyzer.rs @@ -15,6 +15,7 @@ use std::{ collections::BTreeMap, path::Path, sync::{Arc, Mutex}, + thread, }; use move_analyzer::{ @@ -48,10 +49,11 @@ fn main() { ); let (connection, io_threads) = Connection::stdio(); + let symbols = Arc::new(Mutex::new(symbols::Symbolicator::empty_symbols())); let mut context = Context { connection, files: VirtualFileSystem::default(), - symbols: Arc::new(Mutex::new(symbols::Symbolicator::empty_symbols())), + symbols: symbols.clone(), }; let (id, client_response) = context @@ -115,8 +117,7 @@ fn main() { serde_json::from_value(client_response) .expect("could not deserialize client capabilities"); - symbolicator_runner = - symbols::SymbolicatorRunner::new(context.symbols.clone(), diag_sender); + symbolicator_runner = symbols::SymbolicatorRunner::new(symbols.clone(), diag_sender); // If initialization information from the client contains a path to the directory being // opened, try to initialize symbols before sending response to the client. Do not bother @@ -125,11 +126,21 @@ fn main() { // to be available right after the client is initialized. if let Some(uri) = initialize_params.root_uri { if let Some(p) = symbols::SymbolicatorRunner::root_dir(&uri.to_file_path().unwrap()) { - if let Ok((Some(new_symbols), _)) = symbols::Symbolicator::get_symbols(p.as_path()) - { - let mut old_symbols = context.symbols.lock().unwrap(); - (*old_symbols).merge(new_symbols); - } + // need to evaluate in a separate thread to allow for a larger stack size (needed on + // Windows) + thread::Builder::new() + .stack_size(symbols::STACK_SIZE_BYTES) + .spawn(move || { + if let Ok((Some(new_symbols), _)) = + symbols::Symbolicator::get_symbols(p.as_path()) + { + let mut old_symbols = symbols.lock().unwrap(); + (*old_symbols).merge(new_symbols); + } + }) + .unwrap() + .join() + .unwrap(); } } }; diff --git a/language/move-analyzer/src/symbols.rs b/language/move-analyzer/src/symbols.rs index 80c6c2a716..f2717837a1 100644 --- a/language/move-analyzer/src/symbols.rs +++ b/language/move-analyzer/src/symbols.rs @@ -90,6 +90,9 @@ use move_symbol_pool::Symbol; /// Enabling/disabling the language server reporting readiness to support go-to-def and /// go-to-references to the IDE. pub const DEFS_AND_REFS_SUPPORT: bool = true; +// Building Move code requires a larger stack size on Windows (16M has been chosen somewhat +// arbitrarily) +pub const STACK_SIZE_BYTES: usize = 16 * 1024 * 1024; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] /// Location of a definition's identifier @@ -334,7 +337,7 @@ impl SymbolicatorRunner { let runner = SymbolicatorRunner { mtx_cvar }; thread::Builder::new() - .stack_size(16 * 1024 * 1024) // building Move code requires a larger stack size on Windows + .stack_size(STACK_SIZE_BYTES) .spawn(move || { let (mtx, cvar) = &*thread_mtx_cvar; // Locations opened in the IDE (files or directories) for which manifest file is missing From 95d933106228daf24ffe14aa8e8ac2f47ea81df3 Mon Sep 17 00:00:00 2001 From: vgao Date: Fri, 15 Jul 2022 12:14:54 -0700 Subject: [PATCH 006/169] [move-vm] allow gas metering to be customized This adds a trait GasMeter that allows gas metering to be fine-tuned by the clients. Additionally, this also makes native functions closures, allowing them to carry their own contexts, which is now necessary for gas parameters. The original GasStatus and related definitions are also moved from move_vm_types/move_core_types into move_vm_test_utils. --- Cargo.lock | 7 + language/benchmarks/src/move_vm.rs | 10 +- .../diem-framework/crates/cli/Cargo.toml | 1 + .../diem-framework/crates/cli/src/main.rs | 39 +-- .../diem-framework/crates/crypto/Cargo.toml | 3 +- .../crates/natives/src/account.rs | 16 +- .../diem-framework/crates/natives/src/lib.rs | 38 ++- .../crates/natives/src/signature.rs | 22 +- language/documentation/spec/vm.md | 8 +- .../extensions/async/move-async-vm/Cargo.toml | 3 +- .../async/move-async-vm/src/async_vm.rs | 26 +- .../async/move-async-vm/src/natives.rs | 135 ++++++++-- .../async/move-async-vm/tests/testsuite.rs | 11 +- .../move-table-extension/Cargo.toml | 2 +- .../move-table-extension/src/lib.rs | 54 ++-- .../tests/move_unit_tests.rs | 6 +- .../move-binary-format/src/file_format.rs | 2 - language/move-core/types/src/gas_schedule.rs | 122 --------- language/move-stdlib/Cargo.toml | 2 +- language/move-stdlib/src/natives/bcs.rs | 95 +++++-- language/move-stdlib/src/natives/debug.rs | 82 ++++++- language/move-stdlib/src/natives/event.rs | 59 ++++- language/move-stdlib/src/natives/hash.rs | 97 ++++++-- language/move-stdlib/src/natives/helpers.rs | 12 + language/move-stdlib/src/natives/mod.rs | 228 +++++++++++------ language/move-stdlib/src/natives/signer.rs | 53 +++- language/move-stdlib/src/natives/string.rs | 169 +++++++++++-- language/move-stdlib/src/natives/unit_test.rs | 52 +++- language/move-stdlib/src/natives/vector.rs | 225 ++++++++++++++--- language/move-stdlib/tests/move_unit_test.rs | 25 +- .../src/tests/bad_entry_point_tests.rs | 8 +- .../src/tests/bad_storage_tests.rs | 50 ++-- .../src/tests/exec_func_effects_tests.rs | 22 +- .../src/tests/function_arg_tests.rs | 11 +- .../src/tests/loader_tests.rs | 13 +- .../src/tests/mutated_accounts_tests.rs | 12 +- .../src/tests/return_value_tests.rs | 5 +- language/move-vm/runtime/src/interpreter.rs | 185 +++++++------- language/move-vm/runtime/src/loader.rs | 6 +- .../move-vm/runtime/src/native_functions.rs | 21 +- language/move-vm/runtime/src/runtime.rs | 16 +- language/move-vm/runtime/src/session.rs | 26 +- .../src/unit_tests/vm_arguments_tests.rs | 13 +- language/move-vm/test-utils/Cargo.toml | 4 + .../{types => test-utils}/src/gas_schedule.rs | 231 +++++++++++------- language/move-vm/test-utils/src/lib.rs | 1 + language/move-vm/test-utils/src/storage.rs | 25 +- language/move-vm/types/src/gas.rs | 47 ++++ language/move-vm/types/src/lib.rs | 2 +- .../types/src/loaded_data/runtime_types.rs | 29 ++- .../move-vm/types/src/natives/function.rs | 27 +- .../testing-infra/test-generation/src/lib.rs | 6 +- .../src/vm_test_harness.rs | 12 +- language/tools/move-cli/Cargo.toml | 1 + language/tools/move-cli/src/lib.rs | 7 +- language/tools/move-cli/src/main.rs | 15 +- language/tools/move-cli/src/sandbox/cli.rs | 3 +- .../move-cli/src/sandbox/commands/publish.rs | 2 +- .../move-cli/src/sandbox/commands/run.rs | 2 +- .../tools/move-cli/src/sandbox/utils/mod.rs | 3 +- .../tools/move-unit-test/src/test_runner.rs | 30 ++- 61 files changed, 1585 insertions(+), 854 deletions(-) create mode 100644 language/move-stdlib/src/natives/helpers.rs rename language/move-vm/{types => test-utils}/src/gas_schedule.rs (73%) create mode 100644 language/move-vm/types/src/gas.rs diff --git a/Cargo.lock b/Cargo.lock index 2d837b4ff5..58a0a0a47d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1011,6 +1011,7 @@ dependencies = [ "move-cli", "move-core-types", "move-stdlib", + "move-vm-test-utils", "move-vm-types", ] @@ -2322,6 +2323,7 @@ dependencies = [ "move-prover-test-utils", "move-stdlib", "move-vm-runtime", + "move-vm-test-utils", "move-vm-types", "sha3 0.9.1", "smallvec", @@ -2432,6 +2434,7 @@ dependencies = [ "move-table-extension", "move-unit-test", "move-vm-runtime", + "move-vm-test-utils", "move-vm-types", "once_cell", "read-write-set", @@ -3101,8 +3104,12 @@ name = "move-vm-test-utils" version = "0.1.0" dependencies = [ "anyhow", + "move-binary-format", "move-core-types", "move-table-extension", + "move-vm-types", + "once_cell", + "serde 1.0.130", ] [[package]] diff --git a/language/benchmarks/src/move_vm.rs b/language/benchmarks/src/move_vm.rs index 72b4c337e0..46ac387218 100644 --- a/language/benchmarks/src/move_vm.rs +++ b/language/benchmarks/src/move_vm.rs @@ -12,7 +12,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::BlankStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; use once_cell::sync::Lazy; use std::path::PathBuf; @@ -27,6 +27,7 @@ pub fn bench(c: &mut Criterion, fun: &str) { let modules = compile_modules(); let move_vm = MoveVM::new(move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), )) .unwrap(); execute(c, &move_vm, modules, fun); @@ -65,7 +66,8 @@ fn execute( let storage = BlankStorage::new(); let sender = CORE_CODE_ADDRESS; let mut session = move_vm.new_session(&storage); - let mut gas_status = GasStatus::new_unmetered(); + + // TODO: we may want to use a real gas meter to make benchmarks more realistic. for module in modules { let mut mod_blob = vec![]; @@ -73,7 +75,7 @@ fn execute( .serialize(&mut mod_blob) .expect("Module serialization error"); session - .publish_module(mod_blob, sender, &mut gas_status) + .publish_module(mod_blob, sender, &mut UnmeteredGasMeter) .expect("Module must load"); } @@ -90,7 +92,7 @@ fn execute( fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_or_else(|err| { panic!( diff --git a/language/documentation/examples/diem-framework/crates/cli/Cargo.toml b/language/documentation/examples/diem-framework/crates/cli/Cargo.toml index 7976e01e29..9cc4980d10 100644 --- a/language/documentation/examples/diem-framework/crates/cli/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/cli/Cargo.toml @@ -16,6 +16,7 @@ move-stdlib = { path = "../../../../../move-stdlib" } move-core-types = { path = "../../../../../move-core/types" } move-vm-types = { path = "../../../../../move-vm/types" } move-cli = { path = "../../../../../tools/move-cli" } +move-vm-test-utils = { path = "../../../../../move-vm/test-utils" } diem-framework-natives = { path = "../natives" } diff --git a/language/documentation/examples/diem-framework/crates/cli/src/main.rs b/language/documentation/examples/diem-framework/crates/cli/src/main.rs index f974828c32..ec83cef143 100644 --- a/language/documentation/examples/diem-framework/crates/cli/src/main.rs +++ b/language/documentation/examples/diem-framework/crates/cli/src/main.rs @@ -5,12 +5,10 @@ use anyhow::Result; use clap::Parser; use move_cli::{Command, Move}; -use move_core_types::{ - errmap::ErrorMapping, - gas_schedule::{CostTable, GasCost}, - language_storage::CORE_CODE_ADDRESS, +use move_core_types::{errmap::ErrorMapping, language_storage::CORE_CODE_ADDRESS}; +use move_vm_test_utils::gas_schedule::{ + new_from_instructions, zero_cost_instruction_table, CostTable, }; -use move_vm_types::gas_schedule::{new_from_instructions, zero_cost_instruction_table}; #[derive(Parser)] pub struct DfCli { @@ -28,31 +26,36 @@ pub enum DfCommands { // extra commands available only in df-cli can be added below } -fn cost_table(num_natives: usize) -> CostTable { +fn cost_table() -> CostTable { let instruction_table = zero_cost_instruction_table(); - let native_table = std::iter::repeat_with(|| GasCost::new(0, 0)) - .take(num_natives) - .collect(); - - new_from_instructions(instruction_table, native_table) + new_from_instructions(instruction_table) } fn main() -> Result<()> { // let error_descriptions: ErrorMapping = // bcs::from_bytes(diem_framework_releases::current_error_descriptions())?; - let natives = move_stdlib::natives::all_natives(CORE_CODE_ADDRESS) - .into_iter() - .chain(diem_framework_natives::all_natives(CORE_CODE_ADDRESS)) - .collect::>(); - - let num_natives = natives.len(); + let natives = move_stdlib::natives::all_natives( + CORE_CODE_ADDRESS, + // We may want to switch to a different gas schedule in the future, but for now, + // the all-zero one should be enough. + move_stdlib::natives::GasParameters::zeros(), + ) + .into_iter() + .chain(move_stdlib::natives::nursery_natives( + CORE_CODE_ADDRESS, + // We may want to switch to a different gas schedule in the future, but for now, + // the all-zero one should be enough. + move_stdlib::natives::NurseryGasParameters::zeros(), + )) + .chain(diem_framework_natives::all_natives(CORE_CODE_ADDRESS)) + .collect::>(); let args = DfCli::parse(); match args.cmd { DfCommands::Command(cmd) => move_cli::run_cli( natives, - &cost_table(num_natives), + &cost_table(), // TODO: implement this &ErrorMapping::default(), args.move_args, diff --git a/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml b/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml index ceba097221..895d8bf24e 100644 --- a/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml @@ -41,7 +41,8 @@ ripemd160 = "0.9.1" criterion = "0.3.4" sha3 = "0.9.1" serde_json = "1.0.64" -trybuild = "1.0.41" +# TODO: some tests will fail if this is set to 1.0.63 +trybuild = "=1.0.53" [features] default = ["fiat"] diff --git a/language/documentation/examples/diem-framework/crates/natives/src/account.rs b/language/documentation/examples/diem-framework/crates/natives/src/account.rs index 00c063fa00..2bdb568557 100644 --- a/language/documentation/examples/diem-framework/crates/natives/src/account.rs +++ b/language/documentation/examples/diem-framework/crates/natives/src/account.rs @@ -6,17 +6,13 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::account_address::AccountAddress; use move_vm_runtime::native_functions::NativeContext; use move_vm_types::{ - gas_schedule::NativeCostIndex, - loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, - pop_arg, - values::Value, + loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use smallvec::smallvec; use std::collections::VecDeque; pub fn native_create_signer( - context: &mut NativeContext, + _context: &mut NativeContext, ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -24,20 +20,18 @@ pub fn native_create_signer( debug_assert!(arguments.len() == 1); let address = pop_arg!(arguments, AccountAddress); - let cost = native_gas(context.cost_table(), NativeCostIndex::CREATE_SIGNER, 0); - Ok(NativeResult::ok(cost, smallvec![Value::signer(address)])) + Ok(NativeResult::ok(25, smallvec![Value::signer(address)])) } /// NOTE: this function will be deprecated after the Diem v3 release, but must /// remain for replaying old transactions pub fn native_destroy_signer( - context: &mut NativeContext, + _context: &mut NativeContext, ty_args: Vec, arguments: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.is_empty()); debug_assert!(arguments.len() == 1); - let cost = native_gas(context.cost_table(), NativeCostIndex::DESTROY_SIGNER, 0); - Ok(NativeResult::ok(cost, smallvec![])) + Ok(NativeResult::ok(213, smallvec![])) } diff --git a/language/documentation/examples/diem-framework/crates/natives/src/lib.rs b/language/documentation/examples/diem-framework/crates/natives/src/lib.rs index cc85249f32..bb8471f7cd 100644 --- a/language/documentation/examples/diem-framework/crates/natives/src/lib.rs +++ b/language/documentation/examples/diem-framework/crates/natives/src/lib.rs @@ -5,44 +5,42 @@ pub mod account; pub mod signature; -use move_core_types::{account_address::AccountAddress, identifier::Identifier}; -use move_vm_runtime::native_functions::{NativeFunction, NativeFunctionTable}; +use std::sync::Arc; + +use move_core_types::account_address::AccountAddress; +use move_vm_runtime::native_functions::{ + make_table_from_iter, NativeFunction, NativeFunctionTable, +}; pub fn all_natives(diem_framework_addr: AccountAddress) -> NativeFunctionTable { - const NATIVES: &[(&str, &str, NativeFunction)] = &[ + let natives: [(&str, &str, NativeFunction); 5] = [ // TODO: Remove once/if DPN is moved over to use the core framework ( "DiemAccount", "create_signer", - account::native_create_signer, + Arc::new(account::native_create_signer), ), ( "DiemAccount", "destroy_signer", - account::native_destroy_signer, + Arc::new(account::native_destroy_signer), ), ( "Signature", "ed25519_validate_pubkey", - signature::native_ed25519_publickey_validation, + Arc::new(signature::native_ed25519_publickey_validation), ), ( "Signature", "ed25519_verify", - signature::native_ed25519_signature_verification, + Arc::new(signature::native_ed25519_signature_verification), + ), + ( + "Account", + "create_signer", + Arc::new(account::native_create_signer), ), - ("Account", "create_signer", account::native_create_signer), ]; - NATIVES - .iter() - .cloned() - .map(|(module_name, func_name, func)| { - ( - diem_framework_addr, - Identifier::new(module_name).unwrap(), - Identifier::new(func_name).unwrap(), - func, - ) - }) - .collect() + + make_table_from_iter(diem_framework_addr, natives) } diff --git a/language/documentation/examples/diem-framework/crates/natives/src/signature.rs b/language/documentation/examples/diem-framework/crates/natives/src/signature.rs index 911ba1edde..8744a9aa80 100644 --- a/language/documentation/examples/diem-framework/crates/natives/src/signature.rs +++ b/language/documentation/examples/diem-framework/crates/natives/src/signature.rs @@ -6,17 +6,13 @@ use diem_crypto::{ed25519, traits::*}; use move_binary_format::errors::PartialVMResult; use move_vm_runtime::native_functions::NativeContext; use move_vm_types::{ - gas_schedule::NativeCostIndex, - loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, - pop_arg, - values::Value, + loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use smallvec::smallvec; use std::{collections::VecDeque, convert::TryFrom}; pub fn native_ed25519_publickey_validation( - context: &mut NativeContext, + _context: &mut NativeContext, _ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -25,11 +21,7 @@ pub fn native_ed25519_publickey_validation( let key_bytes = pop_arg!(arguments, Vec); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::ED25519_VALIDATE_KEY, - key_bytes.len(), - ); + let cost = 26 * usize::max(key_bytes.len(), 1) as u64; // This deserialization performs point-on-curve and small subgroup checks let valid = ed25519::Ed25519PublicKey::try_from(&key_bytes[..]).is_ok(); @@ -37,7 +29,7 @@ pub fn native_ed25519_publickey_validation( } pub fn native_ed25519_signature_verification( - context: &mut NativeContext, + _context: &mut NativeContext, _ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -48,11 +40,7 @@ pub fn native_ed25519_signature_verification( let pubkey = pop_arg!(arguments, Vec); let signature = pop_arg!(arguments, Vec); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::ED25519_VERIFY, - msg.len(), - ); + let cost = 62 * usize::max(msg.len(), 1) as u64; let sig = match ed25519::Ed25519Signature::try_from(signature.as_slice()) { Ok(sig) => sig, diff --git a/language/documentation/spec/vm.md b/language/documentation/spec/vm.md index 7b4588f1c5..7620a0fc95 100644 --- a/language/documentation/spec/vm.md +++ b/language/documentation/spec/vm.md @@ -75,7 +75,7 @@ pub fn publish_module( &mut self, module: Vec, sender: AccountAddress, - gas_status: &mut GasStatus, + gas_status: &mut impl GasMeter, ) -> VMResult<()>; ``` @@ -120,7 +120,7 @@ pub fn execute_script( ty_args: Vec, args: Vec>, senders: Vec, - gas_status: &mut GasStatus, + gas_status: &mut impl GasMeter, ) -> VMResult<()>; ``` @@ -170,7 +170,7 @@ pub fn execute_script_function( ty_args: Vec, args: Vec>, senders: Vec, - gas_status: &mut GasStatus, + gas_status: &mut impl GasMeter, ) -> VMResult<()>; ``` @@ -201,7 +201,7 @@ pub fn execute_function( function_name: &IdentStr, ty_args: Vec, args: Vec>, - gas_status: &mut GasStatus, + gas_status: &mut impl GasMeter, ) -> VMResult<()>; ``` diff --git a/language/extensions/async/move-async-vm/Cargo.toml b/language/extensions/async/move-async-vm/Cargo.toml index 812745d9d4..0d25f3aa4f 100644 --- a/language/extensions/async/move-async-vm/Cargo.toml +++ b/language/extensions/async/move-async-vm/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Wrapper for the Move VM for the asynchronous execution flavor" repository = "https://github.com/diem/move" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [dependencies] @@ -21,6 +21,7 @@ move-core-types = { path = "../../../move-core/types" } move-compiler = { path = "../../../move-compiler" } move-vm-types = { path = "../../../move-vm/types" } move-vm-runtime = { path = "../../../move-vm/runtime", features = ["debugging"] } +move-vm-test-utils = { path = "../../../move-vm/test-utils" } move-binary-format = { path = "../../../move-binary-format" } [dev-dependencies] diff --git a/language/extensions/async/move-async-vm/src/async_vm.rs b/language/extensions/async/move-async-vm/src/async_vm.rs index 6b6cce61fb..472e4a1c10 100644 --- a/language/extensions/async/move-async-vm/src/async_vm.rs +++ b/language/extensions/async/move-async-vm/src/async_vm.rs @@ -24,13 +24,16 @@ use move_vm_runtime::{ native_functions::NativeFunction, session::{SerializedReturnValues, Session}, }; -use move_vm_types::{ - gas_schedule::GasStatus, - values::{Reference, Value}, +use move_vm_test_utils::gas_schedule::GasStatus; +use move_vm_types::values::{Reference, Value}; + +use crate::{ + actor_metadata, + actor_metadata::ActorMetadata, + natives, + natives::{AsyncExtension, GasParameters as ActorGasParameters}, }; -use crate::{actor_metadata, actor_metadata::ActorMetadata, natives, natives::AsyncExtension}; - /// Represents an instance of an async VM. pub struct AsyncVM { move_vm: MoveVM, @@ -40,7 +43,12 @@ pub struct AsyncVM { impl AsyncVM { /// Creates a new VM, registering the given natives and actors. - pub fn new(async_lib_addr: AccountAddress, natives: I, actors: A) -> VMResult + pub fn new( + async_lib_addr: AccountAddress, + natives: I, + actors: A, + actor_gas_parameters: ActorGasParameters, + ) -> VMResult where I: IntoIterator, A: IntoIterator, @@ -62,9 +70,9 @@ impl AsyncVM { .collect(); Ok(AsyncVM { move_vm: MoveVM::new( - natives - .into_iter() - .chain(natives::actor_natives(async_lib_addr).into_iter()), + natives.into_iter().chain( + natives::actor_natives(async_lib_addr, actor_gas_parameters).into_iter(), + ), )?, actor_metadata, message_table, diff --git a/language/extensions/async/move-async-vm/src/natives.rs b/language/extensions/async/move-async-vm/src/natives.rs index 5b78f372f4..4b85a04054 100644 --- a/language/extensions/async/move-async-vm/src/natives.rs +++ b/language/extensions/async/move-async-vm/src/natives.rs @@ -11,20 +11,13 @@ use move_vm_runtime::{ native_functions::{NativeContext, NativeFunction}, }; use move_vm_types::{ - gas_schedule::NativeCostIndex, loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, + natives::function::NativeResult, pop_arg, values::{Value, Vector}, }; use smallvec::smallvec; -use std::collections::VecDeque; - -// TODO: make cost tables extensible; right now we forward to one of the predefined cost indices -// as an approximation. -const SELF_COST_INDEX: NativeCostIndex = NativeCostIndex::LENGTH; -const SEND_COST_INDEX: NativeCostIndex = NativeCostIndex::EMIT_EVENT; -const EPOCH_TIME_INDEX: NativeCostIndex = NativeCostIndex::LENGTH; +use std::{collections::VecDeque, sync::Arc}; /// Environment extension for the Move VM which we pass down to native functions, /// to implement message sending and retrieval of actor address. @@ -36,39 +29,112 @@ pub struct AsyncExtension { pub in_initializer: bool, } +#[derive(Clone, Debug)] +pub struct GasParameters { + pub self_: SelfGasParameters, + pub send: SendGasParameters, + pub virtual_time: VirtualTimeGasParameters, +} + +impl GasParameters { + pub fn zeros() -> Self { + Self { + self_: SelfGasParameters { base_cost: 0 }, + send: SendGasParameters { + base_cost: 0, + unit_cost: 0, + }, + virtual_time: VirtualTimeGasParameters { base_cost: 0 }, + } + } +} + pub fn actor_natives( async_addr: AccountAddress, + gas_params: GasParameters, ) -> Vec<(AccountAddress, Identifier, Identifier, NativeFunction)> { - const NATIVES: &[(&str, &str, NativeFunction)] = &[ - ("Actor", "self", native_self), - ("Actor", "virtual_time", native_virtual_time), - ("Runtime", "send__0", native_send), - ("Runtime", "send__1", native_send), - ("Runtime", "send__2", native_send), - ("Runtime", "send__3", native_send), - ("Runtime", "send__4", native_send), - ("Runtime", "send__5", native_send), - ("Runtime", "send__6", native_send), - ("Runtime", "send__7", native_send), - ("Runtime", "send__8", native_send), + let natives = [ + ("Actor", "self", make_native_self(gas_params.self_)), + ( + "Actor", + "virtual_time", + make_native_virtual_time(gas_params.virtual_time), + ), + ( + "Runtime", + "send__0", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__1", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__2", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__3", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__4", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__5", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__6", + make_native_send(gas_params.send.clone()), + ), + ( + "Runtime", + "send__7", + make_native_send(gas_params.send.clone()), + ), + ("Runtime", "send__8", make_native_send(gas_params.send)), ]; - native_functions::make_table(async_addr, NATIVES) + native_functions::make_table_from_iter(async_addr, natives) +} + +#[derive(Clone, Debug)] +pub struct SelfGasParameters { + base_cost: u64, } fn native_self( + gas_params: &SelfGasParameters, context: &mut NativeContext, mut _ty_args: Vec, mut _args: VecDeque, ) -> PartialVMResult { - let cost = native_gas(context.cost_table(), SELF_COST_INDEX, 1); let ext = context.extensions().get::(); Ok(NativeResult::ok( - cost, + gas_params.base_cost, smallvec![Value::address(ext.current_actor)], )) } +fn make_native_self(gas_params: SelfGasParameters) -> NativeFunction { + Arc::new(move |context, ty_args, args| native_self(&gas_params, context, ty_args, args)) +} + +#[derive(Clone, Debug)] +pub struct SendGasParameters { + base_cost: u64, + unit_cost: u64, +} + fn native_send( + gas_params: &SendGasParameters, context: &mut NativeContext, mut _ty_args: Vec, mut args: VecDeque, @@ -82,19 +148,34 @@ fn native_send( let message_hash = pop_arg!(args, u64); let target = pop_arg!(args, AccountAddress); ext.sent.push((target, message_hash, bcs_args)); - let cost = native_gas(context.cost_table(), SEND_COST_INDEX, args.len()); + + let cost = gas_params.base_cost + gas_params.unit_cost * args.len() as u64; + Ok(NativeResult::ok(cost, smallvec![])) } +fn make_native_send(gas_params: SendGasParameters) -> NativeFunction { + Arc::new(move |context, ty_args, args| native_send(&gas_params, context, ty_args, args)) +} + +#[derive(Clone, Debug)] +pub struct VirtualTimeGasParameters { + base_cost: u64, +} + fn native_virtual_time( + gas_params: &VirtualTimeGasParameters, context: &mut NativeContext, mut _ty_args: Vec, mut _args: VecDeque, ) -> PartialVMResult { - let cost = native_gas(context.cost_table(), EPOCH_TIME_INDEX, 1); let ext = context.extensions().get::(); Ok(NativeResult::ok( - cost, + gas_params.base_cost, smallvec![Value::u128(ext.virtual_time)], )) } + +fn make_native_virtual_time(gas_params: VirtualTimeGasParameters) -> NativeFunction { + Arc::new(move |context, ty_args, args| native_virtual_time(&gas_params, context, ty_args, args)) +} diff --git a/language/extensions/async/move-async-vm/tests/testsuite.rs b/language/extensions/async/move-async-vm/tests/testsuite.rs index f986693e25..c79dfe03fc 100644 --- a/language/extensions/async/move-async-vm/tests/testsuite.rs +++ b/language/extensions/async/move-async-vm/tests/testsuite.rs @@ -8,6 +8,7 @@ use move_async_vm::{ actor_metadata, actor_metadata::ActorMetadata, async_vm::{AsyncResult, AsyncSession, AsyncVM, Message}, + natives::GasParameters as ActorGasParameters, }; use move_binary_format::access::ModuleAccess; use move_command_line_common::testing::EXP_EXT; @@ -23,7 +24,7 @@ use move_core_types::{ resolver::{ModuleResolver, ResourceResolver}, }; use move_prover_test_utils::{baseline_test::verify_or_update_baseline, extract_test_directives}; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_test_utils::gas_schedule::GasStatus; use std::{ cell::RefCell, collections::{BTreeMap, BTreeSet, VecDeque}, @@ -237,8 +238,14 @@ impl Harness { resource_store: Default::default(), vm: AsyncVM::new( test_account(), - move_stdlib::natives::all_natives(test_account()), + move_stdlib::natives::all_natives( + test_account(), + // We may want to switch to a different gas schedule in the future, but for now, + // the all-zero one should be enough. + move_stdlib::natives::GasParameters::zeros(), + ), actor_metadata, + ActorGasParameters::zeros(), )?, actor_instances, }; diff --git a/language/extensions/move-table-extension/Cargo.toml b/language/extensions/move-table-extension/Cargo.toml index 36e01fd7ab..5cf8b258c8 100644 --- a/language/extensions/move-table-extension/Cargo.toml +++ b/language/extensions/move-table-extension/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Wrapper for the Move VM which coordinates multiple extensions" repository = "https://github.com/diem/move" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [dependencies] diff --git a/language/extensions/move-table-extension/src/lib.rs b/language/extensions/move-table-extension/src/lib.rs index df7687eff8..2f63a91ac5 100644 --- a/language/extensions/move-table-extension/src/lib.rs +++ b/language/extensions/move-table-extension/src/lib.rs @@ -10,15 +10,12 @@ use better_any::{Tid, TidAble}; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{ - account_address::AccountAddress, - gas_schedule::{GasAlgebra, GasCarrier, InternalGasUnits}, - language_storage::TypeTag, - value::MoveTypeLayout, + account_address::AccountAddress, language_storage::TypeTag, value::MoveTypeLayout, vm_status::StatusCode, }; use move_vm_runtime::{ native_functions, - native_functions::{NativeContext, NativeFunctionTable}, + native_functions::{NativeContext, NativeFunction, NativeFunctionTable}, }; use move_vm_types::{ loaded_data::runtime_types::Type, @@ -33,6 +30,7 @@ use std::{ collections::{btree_map::Entry, BTreeMap, BTreeSet, VecDeque}, convert::TryInto, fmt::Display, + sync::Arc, }; // =========================================================================================== @@ -93,12 +91,7 @@ pub trait TableResolver { key: &[u8], ) -> Result>, anyhow::Error>; - fn operation_cost( - &self, - op: TableOperation, - key_size: usize, - val_size: usize, - ) -> InternalGasUnits; + fn operation_cost(&self, op: TableOperation, key_size: usize, val_size: usize) -> u64; } /// A table operation, for supporting cost calculation. @@ -341,19 +334,30 @@ impl Table { /// Returns all natives for tables. pub fn table_natives(table_addr: AccountAddress) -> NativeFunctionTable { - native_functions::make_table( - table_addr, - &[ - ("table", "new_table_handle", native_new_table_handle), - ("table", "add_box", native_add_box), - ("table", "borrow_box", native_borrow_box), - ("table", "borrow_box_mut", native_borrow_box), - ("table", "remove_box", native_remove_box), - ("table", "contains_box", native_contains_box), - ("table", "destroy_empty_box", native_destroy_empty_box), - ("table", "drop_unchecked_box", native_drop_unchecked_box), - ], - ) + let natives: [(&str, &str, NativeFunction); 8] = [ + ( + "table", + "new_table_handle", + Arc::new(native_new_table_handle), + ), + ("table", "add_box", Arc::new(native_add_box)), + ("table", "borrow_box", Arc::new(native_borrow_box)), + ("table", "borrow_box_mut", Arc::new(native_borrow_box)), + ("table", "remove_box", Arc::new(native_remove_box)), + ("table", "contains_box", Arc::new(native_contains_box)), + ( + "table", + "destroy_empty_box", + Arc::new(native_destroy_empty_box), + ), + ( + "table", + "drop_unchecked_box", + Arc::new(native_drop_unchecked_box), + ), + ]; + + native_functions::make_table_from_iter(table_addr, natives) } fn native_new_table_handle( @@ -524,7 +528,7 @@ fn native_drop_unchecked_box( assert_eq!(ty_args.len(), 3); assert_eq!(args.len(), 1); - Ok(NativeResult::ok(InternalGasUnits::new(0_u64), smallvec![])) + Ok(NativeResult::ok(0, smallvec![])) } // ========================================================================================= diff --git a/language/extensions/move-table-extension/tests/move_unit_tests.rs b/language/extensions/move-table-extension/tests/move_unit_tests.rs index d9ed043e8d..b6bf53b7e5 100644 --- a/language/extensions/move-table-extension/tests/move_unit_tests.rs +++ b/language/extensions/move-table-extension/tests/move_unit_tests.rs @@ -11,8 +11,10 @@ use tempfile::tempdir; fn run_tests_for_pkg(path_to_pkg: impl Into) { let pkg_path = path_in_crate(path_to_pkg); - let mut natives = - move_stdlib::natives::all_natives(AccountAddress::from_hex_literal("0x1").unwrap()); + let mut natives = move_stdlib::natives::all_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), + ); natives.append(&mut table_natives( AccountAddress::from_hex_literal("0x2").unwrap(), )); diff --git a/language/move-binary-format/src/file_format.rs b/language/move-binary-format/src/file_format.rs index e6a92f591f..645002f8a5 100644 --- a/language/move-binary-format/src/file_format.rs +++ b/language/move-binary-format/src/file_format.rs @@ -1559,8 +1559,6 @@ pub enum Bytecode { VecSwap(SignatureIndex), } -pub const NUMBER_OF_NATIVE_FUNCTIONS: usize = 18; - impl ::std::fmt::Debug for Bytecode { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match self { diff --git a/language/move-core/types/src/gas_schedule.rs b/language/move-core/types/src/gas_schedule.rs index 1d620d05de..07ac00700c 100644 --- a/language/move-core/types/src/gas_schedule.rs +++ b/language/move-core/types/src/gas_schedule.rs @@ -151,127 +151,5 @@ pub const REFERENCE_SIZE: AbstractMemorySize = AbstractMemorySize(8) /// The size of a struct in bytes pub const STRUCT_SIZE: AbstractMemorySize = AbstractMemorySize(2); -/// For V1 all accounts will be ~800 bytes -pub const DEFAULT_ACCOUNT_SIZE: AbstractMemorySize = AbstractMemorySize(800); - -/// Any transaction over this size will be charged `INTRINSIC_GAS_PER_BYTE` per byte -pub const LARGE_TRANSACTION_CUTOFF: AbstractMemorySize = AbstractMemorySize(600); - /// For exists checks on data that doesn't exists this is the multiplier that is used. pub const MIN_EXISTS_DATA_SIZE: AbstractMemorySize = AbstractMemorySize(100); - -pub const MAX_TRANSACTION_SIZE_IN_BYTES: GasCarrier = 4096; - -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] -pub struct GasConstants { - /// The cost per-byte read from global storage. - pub global_memory_per_byte_cost: InternalGasUnits, - - /// The cost per-byte written to storage. - pub global_memory_per_byte_write_cost: InternalGasUnits, - - /// The flat minimum amount of gas required for any transaction. - /// Charged at the start of execution. - pub min_transaction_gas_units: InternalGasUnits, - - /// Any transaction over this size will be charged an additional amount per byte. - pub large_transaction_cutoff: AbstractMemorySize, - - /// The units of gas that to be charged per byte over the `large_transaction_cutoff` in addition to - /// `min_transaction_gas_units` for transactions whose size exceeds `large_transaction_cutoff`. - pub intrinsic_gas_per_byte: InternalGasUnits, - - /// ~5 microseconds should equal one unit of computational gas. We bound the maximum - /// computational time of any given transaction at roughly 20 seconds. We want this number and - /// `MAX_PRICE_PER_GAS_UNIT` to always satisfy the inequality that - /// MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits::MAX) - /// NB: The bound is set quite high since custom scripts aren't allowed except from predefined - /// and vetted senders. - pub maximum_number_of_gas_units: GasUnits, - - /// The minimum gas price that a transaction can be submitted with. - pub min_price_per_gas_unit: GasPrice, - - /// The maximum gas unit price that a transaction can be submitted with. - pub max_price_per_gas_unit: GasPrice, - - pub max_transaction_size_in_bytes: GasCarrier, - - pub gas_unit_scaling_factor: GasCarrier, - pub default_account_size: AbstractMemorySize, -} - -impl GasConstants { - pub fn to_internal_units(&self, units: GasUnits) -> InternalGasUnits { - InternalGasUnits::new(units.get() * self.gas_unit_scaling_factor) - } - - pub fn to_external_units(&self, units: InternalGasUnits) -> GasUnits { - GasUnits::new(units.get() / self.gas_unit_scaling_factor) - } -} - -impl Default for GasConstants { - fn default() -> Self { - Self { - global_memory_per_byte_cost: InternalGasUnits(4), - global_memory_per_byte_write_cost: InternalGasUnits(9), - min_transaction_gas_units: InternalGasUnits(600), - large_transaction_cutoff: LARGE_TRANSACTION_CUTOFF, - intrinsic_gas_per_byte: InternalGasUnits(8), - maximum_number_of_gas_units: GasUnits(4_000_000), - min_price_per_gas_unit: GasPrice(0), - max_price_per_gas_unit: GasPrice(10_000), - max_transaction_size_in_bytes: MAX_TRANSACTION_SIZE_IN_BYTES, - gas_unit_scaling_factor: 1000, - default_account_size: DEFAULT_ACCOUNT_SIZE, - } - } -} -/// The cost tables, keyed by the serialized form of the bytecode instruction. We use the -/// serialized form as opposed to the instruction enum itself as the key since this will be the -/// on-chain representation of bytecode instructions in the future. -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] -pub struct CostTable { - pub instruction_table: Vec, - pub native_table: Vec, - pub gas_constants: GasConstants, -} - -impl CostTable { - #[inline] - pub fn instruction_cost(&self, instr_index: u8) -> &GasCost { - debug_assert!(instr_index > 0 && instr_index <= (self.instruction_table.len() as u8)); - &self.instruction_table[(instr_index - 1) as usize] - } - - #[inline] - pub fn native_cost(&self, native_index: u8) -> &GasCost { - debug_assert!(native_index < (self.native_table.len() as u8)); - &self.native_table[native_index as usize] - } -} - -/// The `GasCost` tracks: -/// - instruction cost: how much time/computational power is needed to perform the instruction -/// - memory cost: how much memory is required for the instruction, and storage overhead -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct GasCost { - pub instruction_gas: InternalGasUnits, - pub memory_gas: InternalGasUnits, -} - -impl GasCost { - pub fn new(instr_gas: GasCarrier, mem_gas: GasCarrier) -> Self { - Self { - instruction_gas: InternalGasUnits::new(instr_gas), - memory_gas: InternalGasUnits::new(mem_gas), - } - } - - /// Convert a GasCost to a total gas charge in `InternalGasUnits`. - #[inline] - pub fn total(&self) -> InternalGasUnits { - self.instruction_gas.add(self.memory_gas) - } -} diff --git a/language/move-stdlib/Cargo.toml b/language/move-stdlib/Cargo.toml index 5ed780418b..2e9261b821 100644 --- a/language/move-stdlib/Cargo.toml +++ b/language/move-stdlib/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "move-stdlib" version = "0.1.1" -edition = "2018" +edition = "2021" authors = ["Diem Association "] description = "Diem stdlib" repository = "https://github.com/diem/diem" diff --git a/language/move-stdlib/src/natives/bcs.rs b/language/move-stdlib/src/natives/bcs.rs index a0d075f8f1..75e942cc5e 100644 --- a/language/move-stdlib/src/natives/bcs.rs +++ b/language/move-stdlib/src/natives/bcs.rs @@ -2,21 +2,43 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_core_types::vm_status::sub_status::NFE_BCS_SERIALIZATION_FAILURE; -use move_vm_runtime::native_functions::NativeContext; +use move_core_types::{ + gas_schedule::GasAlgebra, vm_status::sub_status::NFE_BCS_SERIALIZATION_FAILURE, +}; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, + natives::function::NativeResult, pop_arg, values::{values_impl::Reference, Value}, }; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; +/*************************************************************************************************** + * native fun to_bytes + * + * gas cost: size_of(val_type) * input_unit_cost + | get type layout + * size_of(val) * input_unit_cost + | serialize value + * max(size_of(output), 1) * output_unit_cost + * + * If any of the first two steps fails, a partical cost + an additonal failure_cost + * will be charged. + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct ToBytesGasParameters { + pub input_unit_cost: u64, + pub output_unit_cost: u64, + pub legacy_min_output_size: usize, + pub failure_cost: u64, +} /// Rust implementation of Move's `native public fun to_bytes(&T): vector` -pub fn native_to_bytes( +#[inline] +fn native_to_bytes( + gas_params: &ToBytesGasParameters, context: &mut NativeContext, mut ty_args: Vec, mut args: VecDeque, @@ -24,31 +46,62 @@ pub fn native_to_bytes( debug_assert!(ty_args.len() == 1); debug_assert!(args.len() == 1); - let ref_to_val = pop_arg!(args, Reference); + let mut cost = 0; + // pop type and value + let ref_to_val = pop_arg!(args, Reference); let arg_type = ty_args.pop().unwrap(); - // delegate to the BCS serialization for `Value` - let serialized_value_opt = match context.type_to_type_layout(&arg_type)? { - None => None, - Some(layout) => ref_to_val.read_ref()?.simple_serialize(&layout), - }; - let serialized_value = match serialized_value_opt { + + // get type layout + if gas_params.input_unit_cost != 0 { + cost += gas_params.input_unit_cost * arg_type.size().get() + } + let layout = match context.type_to_type_layout(&arg_type)? { + Some(layout) => layout, None => { - let cost = native_gas(context.cost_table(), NativeCostIndex::BCS_TO_BYTES, 1); + cost += gas_params.failure_cost; return Ok(NativeResult::err(cost, NFE_BCS_SERIALIZATION_FAILURE)); } + }; + // serialize value + let val = ref_to_val.read_ref()?; + if gas_params.input_unit_cost != 0 { + cost += gas_params.input_unit_cost * val.size().get() + } + let serialized_value = match val.simple_serialize(&layout) { Some(serialized_value) => serialized_value, + None => { + cost += gas_params.failure_cost; + return Ok(NativeResult::err(cost, NFE_BCS_SERIALIZATION_FAILURE)); + } }; - - // cost is proportional to the size of the serialized value - let cost = native_gas( - context.cost_table(), - NativeCostIndex::BCS_TO_BYTES, - serialized_value.len(), - ); + cost += gas_params.output_unit_cost + * usize::max(serialized_value.len(), gas_params.legacy_min_output_size) as u64; Ok(NativeResult::ok( cost, smallvec![Value::vector_u8(serialized_value)], )) } + +pub fn make_native_to_bytes(gas_params: ToBytesGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_to_bytes(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub to_bytes: ToBytesGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [("to_bytes", make_native_to_bytes(gas_params.to_bytes))]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/src/natives/debug.rs b/language/move-stdlib/src/natives/debug.rs index b2c4701854..38d6440cb8 100644 --- a/language/move-stdlib/src/natives/debug.rs +++ b/language/move-stdlib/src/natives/debug.rs @@ -2,9 +2,9 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_core_types::gas_schedule::ONE_GAS_UNIT; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; #[allow(unused_imports)] use move_vm_types::values::{values_impl::debug::print_reference, Reference}; #[allow(unused_imports)] @@ -12,12 +12,22 @@ use move_vm_types::{ loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; -#[allow(unused_mut)] -#[allow(unused_variables)] -pub fn native_print( - context: &mut NativeContext, +/*************************************************************************************************** + * native fun print + * + * gas cost: base_cost + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct PrintGasParameters { + pub base_cost: u64, +} + +#[inline] +fn native_print( + gas_params: &PrintGasParameters, + _context: &mut NativeContext, mut ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -27,7 +37,7 @@ pub fn native_print( // No-op if the feature flag is not present. #[cfg(feature = "testing")] { - let ty = ty_args.pop().unwrap(); + let _ty = ty_args.pop().unwrap(); let r = pop_arg!(args, Reference); let mut buf = String::new(); @@ -35,11 +45,30 @@ pub fn native_print( println!("[debug] {}", buf); } - Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![])) + Ok(NativeResult::ok(gas_params.base_cost, smallvec![])) +} + +pub fn make_native_print(gas_params: PrintGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_print(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun print_stack_trace + * + * gas cost: base_cost + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct PrintStackTraceGasParameters { + pub base_cost: u64, } -#[allow(unused_variables)] -pub fn native_print_stack_trace( +#[inline] +fn native_print_stack_trace( + gas_params: &PrintStackTraceGasParameters, context: &mut NativeContext, ty_args: Vec, args: VecDeque, @@ -54,5 +83,34 @@ pub fn native_print_stack_trace( println!("{}", s); } - Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![])) + Ok(NativeResult::ok(gas_params.base_cost, smallvec![])) +} + +pub fn make_native_print_stack_trace(gas_params: PrintStackTraceGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_print_stack_trace(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub print: PrintGasParameters, + pub print_stack_trace: PrintStackTraceGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [ + ("print", make_native_print(gas_params.print)), + ( + "print_stack_trace", + make_native_print_stack_trace(gas_params.print_stack_trace), + ), + ]; + + make_module_natives(natives) } diff --git a/language/move-stdlib/src/natives/event.rs b/language/move-stdlib/src/natives/event.rs index 802564c19e..364f904d0a 100644 --- a/language/move-stdlib/src/natives/event.rs +++ b/language/move-stdlib/src/natives/event.rs @@ -2,20 +2,30 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; use move_core_types::gas_schedule::GasAlgebra; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, - loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, - pop_arg, - values::Value, + loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; -pub fn write_to_event_store( +/*************************************************************************************************** + * [NURSERY-ONLY] native fun write_to_event_store + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct WriteToEventStoreGasParameters { + pub unit_cost: u64, +} + +#[inline] +fn native_write_to_event_store( + gas_params: &WriteToEventStoreGasParameters, context: &mut NativeContext, mut ty_args: Vec, mut arguments: VecDeque, @@ -28,11 +38,7 @@ pub fn write_to_event_store( let seq_num = pop_arg!(arguments, u64); let guid = pop_arg!(arguments, Vec); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::EMIT_EVENT, - msg.size().get() as usize, - ); + let cost = gas_params.unit_cost * u64::max(msg.size().get(), 1); if !context.save_event(guid, seq_num, ty, msg)? { return Ok(NativeResult::err(cost, 0)); @@ -40,3 +46,30 @@ pub fn write_to_event_store( Ok(NativeResult::ok(cost, smallvec![])) } + +pub fn make_native_write_to_event_store( + gas_params: WriteToEventStoreGasParameters, +) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_write_to_event_store(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub write_to_event_store: WriteToEventStoreGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [( + "write_to_event_store", + make_native_write_to_event_store(gas_params.write_to_event_store), + )]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/src/natives/hash.rs b/language/move-stdlib/src/natives/hash.rs index 62e9b8cc4d..0ce953f477 100644 --- a/language/move-stdlib/src/natives/hash.rs +++ b/language/move-stdlib/src/natives/hash.rs @@ -2,22 +2,34 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, - loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, - pop_arg, - values::Value, + loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use sha2::{Digest, Sha256}; use sha3::Sha3_256; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; -pub fn native_sha2_256( - context: &mut NativeContext, +/*************************************************************************************************** + * native fun sha2_256 + * + * gas cost: base_cost + unit_cost * max(input_length_in_bytes, legacy_min_input_len) + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct Sha2_256GasParameters { + pub base_cost: u64, + pub unit_cost: u64, + pub legacy_min_input_len: usize, +} + +#[inline] +fn native_sha2_256( + gas_params: &Sha2_256GasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -26,11 +38,8 @@ pub fn native_sha2_256( let hash_arg = pop_arg!(arguments, Vec); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::SHA2_256, - hash_arg.len(), - ); + let cost = gas_params.base_cost + + gas_params.unit_cost * usize::max(hash_arg.len(), gas_params.legacy_min_input_len) as u64; let hash_vec = Sha256::digest(hash_arg.as_slice()).to_vec(); Ok(NativeResult::ok( @@ -39,8 +48,31 @@ pub fn native_sha2_256( )) } -pub fn native_sha3_256( - context: &mut NativeContext, +pub fn make_native_sha2_256(gas_params: Sha2_256GasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_sha2_256(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun sha3_256 + * + * gas cost: base_cost + unit_cost * max(input_length_in_bytes, legacy_min_input_len) + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct Sha3_256GasParameters { + pub base_cost: u64, + pub unit_cost: u64, + pub legacy_min_input_len: usize, +} + +#[inline] +fn native_sha3_256( + gas_params: &Sha3_256GasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -49,11 +81,8 @@ pub fn native_sha3_256( let hash_arg = pop_arg!(arguments, Vec); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::SHA3_256, - hash_arg.len(), - ); + let cost = gas_params.base_cost + + gas_params.unit_cost * usize::max(hash_arg.len(), gas_params.legacy_min_input_len) as u64; let hash_vec = Sha3_256::digest(hash_arg.as_slice()).to_vec(); Ok(NativeResult::ok( @@ -61,3 +90,29 @@ pub fn native_sha3_256( smallvec![Value::vector_u8(hash_vec)], )) } + +pub fn make_native_sha3_256(gas_params: Sha3_256GasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_sha3_256(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub sha2_256: Sha2_256GasParameters, + pub sha3_256: Sha3_256GasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [ + ("sha2_256", make_native_sha2_256(gas_params.sha2_256)), + ("sha3_256", make_native_sha3_256(gas_params.sha3_256)), + ]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/src/natives/helpers.rs b/language/move-stdlib/src/natives/helpers.rs new file mode 100644 index 0000000000..1a8b8a88cf --- /dev/null +++ b/language/move-stdlib/src/natives/helpers.rs @@ -0,0 +1,12 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use move_vm_runtime::native_functions::NativeFunction; + +pub fn make_module_natives( + natives: impl IntoIterator, NativeFunction)>, +) -> impl Iterator { + natives + .into_iter() + .map(|(func_name, func)| (func_name.into(), func)) +} diff --git a/language/move-stdlib/src/natives/mod.rs b/language/move-stdlib/src/natives/mod.rs index e9272c6abf..d2b9655670 100644 --- a/language/move-stdlib/src/natives/mod.rs +++ b/language/move-stdlib/src/natives/mod.rs @@ -7,90 +7,164 @@ pub mod event; pub mod hash; pub mod signer; pub mod string; -pub mod vector; - #[cfg(feature = "testing")] pub mod unit_test; +pub mod vector; #[cfg(feature = "testing")] pub mod debug; +mod helpers; + use move_core_types::account_address::AccountAddress; -use move_vm_runtime::{ - native_functions, - native_functions::{NativeFunction, NativeFunctionTable}, -}; - -pub fn all_natives(move_std_addr: AccountAddress) -> NativeFunctionTable { - const NATIVES: &[(&str, &str, NativeFunction)] = &[ - ("bcs", "to_bytes", bcs::native_to_bytes), - ("event", "write_to_event_store", event::write_to_event_store), - ("hash", "sha2_256", hash::native_sha2_256), - ("hash", "sha3_256", hash::native_sha3_256), - ("signer", "borrow_address", signer::native_borrow_address), - ("string", "internal_check_utf8", string::native_check_utf8), - ( - "string", - "internal_is_char_boundary", - string::native_is_char_boundary, - ), - ("string", "internal_sub_string", string::native_sub_string), - ("string", "internal_index_of", string::native_index_of), - ("vector", "length", vector::native_length), - ("vector", "empty", vector::native_empty), - ("vector", "borrow", vector::native_borrow), - ("vector", "borrow_mut", vector::native_borrow), - ("vector", "push_back", vector::native_push_back), - ("vector", "pop_back", vector::native_pop), - ("vector", "destroy_empty", vector::native_destroy_empty), - ("vector", "swap", vector::native_swap), - #[cfg(feature = "testing")] - ("debug", "print", debug::native_print), - #[cfg(feature = "testing")] - ( - "debug", - "print_stack_trace", - debug::native_print_stack_trace, - ), - #[cfg(feature = "testing")] - ( - "unit_test", - "create_signers_for_testing", - unit_test::native_create_signers_for_testing, - ), - ]; - native_functions::make_table(move_std_addr, NATIVES) +use move_vm_runtime::native_functions::{make_table_from_iter, NativeFunctionTable}; + +#[derive(Debug, Clone)] +pub struct GasParameters { + bcs: bcs::GasParameters, + hash: hash::GasParameters, + signer: signer::GasParameters, + string: string::GasParameters, + vector: vector::GasParameters, + + #[cfg(feature = "testing")] + unit_test: unit_test::GasParameters, +} + +impl GasParameters { + pub fn zeros() -> Self { + Self { + bcs: bcs::GasParameters { + to_bytes: bcs::ToBytesGasParameters { + input_unit_cost: 0, + output_unit_cost: 0, + legacy_min_output_size: 0, + failure_cost: 0, + }, + }, + + hash: hash::GasParameters { + sha2_256: hash::Sha2_256GasParameters { + base_cost: 0, + unit_cost: 0, + legacy_min_input_len: 0, + }, + sha3_256: hash::Sha3_256GasParameters { + base_cost: 0, + unit_cost: 0, + legacy_min_input_len: 0, + }, + }, + signer: signer::GasParameters { + borrow_address: signer::BorrowAddressGasParameters { base_cost: 0 }, + }, + string: string::GasParameters { + check_utf8: string::CheckUtf8GasParameters { + base_cost: 0, + unit_cost: 0, + }, + is_char_boundary: string::IsCharBoundaryGasParameters { base_cost: 0 }, + sub_string: string::SubStringGasParameters { + base_cost: 0, + unit_cost: 0, + }, + index_of: string::IndexOfGasParameters { + base_cost: 0, + unit_cost: 0, + }, + }, + vector: vector::GasParameters { + empty: vector::EmptyGasParameters { base_cost: 0 }, + length: vector::LengthGasParameters { base_cost: 0 }, + push_back: vector::PushBackGasParameters { + base_cost: 0, + legacy_unit_cost: 0, + }, + borrow: vector::BorrowGasParameters { base_cost: 0 }, + pop_back: vector::PopBackGasParameters { base_cost: 0 }, + destroy_empty: vector::DestroyEmptyGasParameters { base_cost: 0 }, + swap: vector::SwapGasParameters { base_cost: 0 }, + }, + #[cfg(feature = "testing")] + unit_test: unit_test::GasParameters { + create_signers_for_testing: unit_test::CreateSignersForTestingGasParameters { + base_cost: 0, + unit_cost: 0, + }, + }, + } + } +} + +pub fn all_natives( + move_std_addr: AccountAddress, + gas_params: GasParameters, +) -> NativeFunctionTable { + let mut natives = vec![]; + + macro_rules! add_natives { + ($module_name: expr, $natives: expr) => { + natives.extend( + $natives.map(|(func_name, func)| ($module_name.to_string(), func_name, func)), + ); + }; + } + + add_natives!("bcs", bcs::make_all(gas_params.bcs)); + add_natives!("hash", hash::make_all(gas_params.hash)); + add_natives!("signer", signer::make_all(gas_params.signer)); + add_natives!("string", string::make_all(gas_params.string)); + add_natives!("vector", vector::make_all(gas_params.vector)); + #[cfg(feature = "testing")] + { + add_natives!("unit_test", unit_test::make_all(gas_params.unit_test)); + } + + make_table_from_iter(move_std_addr, natives) +} + +#[derive(Debug, Clone)] +pub struct NurseryGasParameters { + event: event::GasParameters, + + #[cfg(feature = "testing")] + debug: debug::GasParameters, } -pub fn all_natives_old_names(move_std_addr: AccountAddress) -> NativeFunctionTable { - const NATIVES: &[(&str, &str, NativeFunction)] = &[ - ("BCS", "to_bytes", bcs::native_to_bytes), - ("Event", "write_to_event_store", event::write_to_event_store), - ("Hash", "sha2_256", hash::native_sha2_256), - ("Hash", "sha3_256", hash::native_sha3_256), - ("Signer", "borrow_address", signer::native_borrow_address), - ("Vector", "length", vector::native_length), - ("Vector", "empty", vector::native_empty), - ("Vector", "borrow", vector::native_borrow), - ("Vector", "borrow_mut", vector::native_borrow), - ("Vector", "push_back", vector::native_push_back), - ("Vector", "pop_back", vector::native_pop), - ("Vector", "destroy_empty", vector::native_destroy_empty), - ("Vector", "swap", vector::native_swap), - #[cfg(feature = "testing")] - ("Debug", "print", debug::native_print), - #[cfg(feature = "testing")] - ( - "Debug", - "print_stack_trace", - debug::native_print_stack_trace, - ), - #[cfg(feature = "testing")] - ( - "UnitTest", - "create_signers_for_testing", - unit_test::native_create_signers_for_testing, - ), - ]; - native_functions::make_table(move_std_addr, NATIVES) +impl NurseryGasParameters { + pub fn zeros() -> Self { + Self { + event: event::GasParameters { + write_to_event_store: event::WriteToEventStoreGasParameters { unit_cost: 0 }, + }, + #[cfg(feature = "testing")] + debug: debug::GasParameters { + print: debug::PrintGasParameters { base_cost: 0 }, + print_stack_trace: debug::PrintStackTraceGasParameters { base_cost: 0 }, + }, + } + } +} + +pub fn nursery_natives( + move_std_addr: AccountAddress, + gas_params: NurseryGasParameters, +) -> NativeFunctionTable { + let mut natives = vec![]; + + macro_rules! add_natives { + ($module_name: expr, $natives: expr) => { + natives.extend( + $natives.map(|(func_name, func)| ($module_name.to_string(), func_name, func)), + ); + }; + } + + add_natives!("event", event::make_all(gas_params.event)); + #[cfg(feature = "testing")] + { + add_natives!("debug", debug::make_all(gas_params.debug)); + } + + make_table_from_iter(move_std_addr, natives) } diff --git a/language/move-stdlib/src/natives/signer.rs b/language/move-stdlib/src/natives/signer.rs index b9da26847f..8961f9b172 100644 --- a/language/move-stdlib/src/natives/signer.rs +++ b/language/move-stdlib/src/natives/signer.rs @@ -2,20 +2,33 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, + natives::function::NativeResult, pop_arg, values::{values_impl::SignerRef, Value}, }; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; -pub fn native_borrow_address( - context: &mut NativeContext, +/*************************************************************************************************** + * native fun borrow_address + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct BorrowAddressGasParameters { + pub base_cost: u64, +} + +#[inline] +fn native_borrow_address( + gas_params: &BorrowAddressGasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut arguments: VecDeque, ) -> PartialVMResult { @@ -23,10 +36,34 @@ pub fn native_borrow_address( debug_assert!(arguments.len() == 1); let signer_reference = pop_arg!(arguments, SignerRef); - let cost = native_gas(context.cost_table(), NativeCostIndex::SIGNER_BORROW, 1); Ok(NativeResult::ok( - cost, + gas_params.base_cost, smallvec![signer_reference.borrow_signer()?], )) } + +pub fn make_native_borrow_address(gas_params: BorrowAddressGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_borrow_address(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub borrow_address: BorrowAddressGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [( + "borrow_address", + make_native_borrow_address(gas_params.borrow_address), + )]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/src/natives/string.rs b/language/move-stdlib/src/natives/string.rs index 0266fe2654..74eb9b8b8e 100644 --- a/language/move-stdlib/src/natives/string.rs +++ b/language/move-stdlib/src/natives/string.rs @@ -4,17 +4,16 @@ //! Implementation of native functions for utf8 strings. +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, + natives::function::NativeResult, pop_arg, values::{Value, VectorRef}, }; - -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; // The implementation approach delegates all utf8 handling to Rust. // This is possible without copying of bytes because (a) we can @@ -24,8 +23,21 @@ use std::collections::VecDeque; // create a `&str` view on the bytes without a copy. Once we have this // view, we can call ut8 functions like length, substring, etc. -pub fn native_check_utf8( - context: &mut NativeContext, +/*************************************************************************************************** + * native fun internal_check_utf8 + * + * gas cost: base_cost + unit_cost * length_in_bytes + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct CheckUtf8GasParameters { + pub base_cost: u64, + pub unit_cost: u64, +} + +fn native_check_utf8( + gas_params: &CheckUtf8GasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -34,12 +46,34 @@ pub fn native_check_utf8( let s_ref = s_arg.as_bytes_ref(); let ok = std::str::from_utf8(s_ref.as_slice()).is_ok(); // TODO: extensible native cost tables - let cost = native_gas(context.cost_table(), NativeCostIndex::PUSH_BACK, 1); + + let cost = gas_params.base_cost + gas_params.unit_cost * s_ref.as_slice().len() as u64; + NativeResult::map_partial_vm_result_one(cost, Ok(Value::bool(ok))) } -pub fn native_is_char_boundary( - context: &mut NativeContext, +pub fn make_native_check_utf8(gas_params: CheckUtf8GasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_check_utf8(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun internal_is_char_boundary + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct IsCharBoundaryGasParameters { + pub base_cost: u64, +} + +fn native_is_char_boundary( + gas_params: &IsCharBoundaryGasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -51,19 +85,44 @@ pub fn native_is_char_boundary( // This is safe because we guarantee the bytes to be utf8. std::str::from_utf8_unchecked(s_ref.as_slice()).is_char_boundary(i as usize) }; - // TODO: extensible native cost tables - let cost = native_gas(context.cost_table(), NativeCostIndex::PUSH_BACK, 1); - NativeResult::map_partial_vm_result_one(cost, Ok(Value::bool(ok))) + NativeResult::map_partial_vm_result_one(gas_params.base_cost, Ok(Value::bool(ok))) +} + +pub fn make_native_is_char_boundary(gas_params: IsCharBoundaryGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_is_char_boundary(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun internal_sub_string + * + * gas cost: base_cost + unit_cost * sub_string_length_in_bytes + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct SubStringGasParameters { + pub base_cost: u64, + pub unit_cost: u64, } -pub fn native_sub_string( - context: &mut NativeContext, +fn native_sub_string( + gas_params: &SubStringGasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { debug_assert!(args.len() == 3); let j = pop_arg!(args, u64) as usize; let i = pop_arg!(args, u64) as usize; + + if j < i { + // TODO: what abort code should we use here? + return Ok(NativeResult::err(gas_params.base_cost, 1)); + } + let s_arg = pop_arg!(args, VectorRef); let s_ref = s_arg.as_bytes_ref(); let s_str = unsafe { @@ -71,13 +130,34 @@ pub fn native_sub_string( std::str::from_utf8_unchecked(s_ref.as_slice()) }; let v = Value::vector_u8((&s_str[i..j]).as_bytes().iter().cloned()); - // TODO: extensible native cost tables - let cost = native_gas(context.cost_table(), NativeCostIndex::PUSH_BACK, 1); + + let cost = gas_params.base_cost + gas_params.unit_cost * (j - i) as u64; NativeResult::map_partial_vm_result_one(cost, Ok(v)) } -pub fn native_index_of( - context: &mut NativeContext, +pub fn make_native_sub_string(gas_params: SubStringGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_sub_string(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun internal_index_of + * + * gas cost: base_cost + unit_cost * bytes_searched + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct IndexOfGasParameters { + pub base_cost: u64, + pub unit_cost: u64, +} + +fn native_index_of( + gas_params: &IndexOfGasParameters, + _context: &mut NativeContext, _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -92,7 +172,54 @@ pub fn native_index_of( Some(size) => size, None => s_str.len(), }; - // TODO: extensible native cost tables - let cost = native_gas(context.cost_table(), NativeCostIndex::LENGTH, 1); + let cost = gas_params.base_cost + + gas_params.unit_cost + * if pos < s_str.len() { + pos + r_str.len() + } else { + pos + } as u64; NativeResult::map_partial_vm_result_one(cost, Ok(Value::u64(pos as u64))) } + +pub fn make_native_index_of(gas_params: IndexOfGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_index_of(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub check_utf8: CheckUtf8GasParameters, + pub is_char_boundary: IsCharBoundaryGasParameters, + pub sub_string: SubStringGasParameters, + pub index_of: IndexOfGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [ + ( + "internal_check_utf8", + make_native_check_utf8(gas_params.check_utf8), + ), + ( + "internal_is_char_boundary", + make_native_is_char_boundary(gas_params.is_char_boundary), + ), + ( + "internal_sub_string", + make_native_sub_string(gas_params.sub_string), + ), + ( + "internal_index_of", + make_native_index_of(gas_params.index_of), + ), + ]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/src/natives/unit_test.rs b/language/move-stdlib/src/natives/unit_test.rs index e68ae3454c..6600fe2b3b 100644 --- a/language/move-stdlib/src/natives/unit_test.rs +++ b/language/move-stdlib/src/natives/unit_test.rs @@ -2,17 +2,23 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; -use move_core_types::gas_schedule::ONE_GAS_UNIT; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, }; use smallvec::smallvec; -use std::collections::VecDeque; +use std::{collections::VecDeque, sync::Arc}; use move_core_types::account_address::AccountAddress; +/*************************************************************************************************** + * native fun create_signers_for_testing + * + * gas cost: base_cost + unit_cost * num_of_signers + * + **************************************************************************************************/ fn to_le_bytes(i: u64) -> [u8; AccountAddress::LENGTH] { let bytes = i.to_le_bytes(); let mut result = [0u8; AccountAddress::LENGTH]; @@ -20,7 +26,14 @@ fn to_le_bytes(i: u64) -> [u8; AccountAddress::LENGTH] { result } -pub fn native_create_signers_for_testing( +#[derive(Debug, Clone)] +pub struct CreateSignersForTestingGasParameters { + pub base_cost: u64, + pub unit_cost: u64, +} + +fn native_create_signers_for_testing( + gas_params: &CreateSignersForTestingGasParameters, _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, @@ -33,5 +46,34 @@ pub fn native_create_signers_for_testing( (0..num_signers).map(|i| Value::signer(AccountAddress::new(to_le_bytes(i)))), ); - Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![signers])) + let cost = gas_params.base_cost + gas_params.unit_cost * num_signers; + + Ok(NativeResult::ok(cost, smallvec![signers])) +} + +pub fn make_native_create_signers_for_testing( + gas_params: CreateSignersForTestingGasParameters, +) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_create_signers_for_testing(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub create_signers_for_testing: CreateSignersForTestingGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [( + "create_signers_for_testing", + make_native_create_signers_for_testing(gas_params.create_signers_for_testing), + )]; + + make_module_natives(natives) } diff --git a/language/move-stdlib/src/natives/vector.rs b/language/move-stdlib/src/natives/vector.rs index d312b6cc32..0e7985e038 100644 --- a/language/move-stdlib/src/natives/vector.rs +++ b/language/move-stdlib/src/natives/vector.rs @@ -2,33 +2,65 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::natives::helpers::make_module_natives; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{gas_schedule::GasAlgebra, vm_status::StatusCode}; -use move_vm_runtime::native_functions::NativeContext; +use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - gas_schedule::NativeCostIndex, loaded_data::runtime_types::Type, - natives::function::{native_gas, NativeResult}, + natives::function::NativeResult, pop_arg, values::{Value, Vector, VectorRef}, }; +use std::sync::Arc; use std::collections::VecDeque; +/*************************************************************************************************** + * native fun empty + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct EmptyGasParameters { + pub base_cost: u64, +} + pub fn native_empty( - context: &mut NativeContext, + gas_params: &EmptyGasParameters, + _context: &mut NativeContext, ty_args: Vec, args: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.len() == 1); debug_assert!(args.is_empty()); - let cost = native_gas(context.cost_table(), NativeCostIndex::EMPTY, 1); - NativeResult::map_partial_vm_result_one(cost, Vector::empty(&ty_args[0])) + NativeResult::map_partial_vm_result_one(gas_params.base_cost, Vector::empty(&ty_args[0])) +} + +pub fn make_native_empty(gas_params: EmptyGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_empty(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun length + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct LengthGasParameters { + pub base_cost: u64, } pub fn native_length( - context: &mut NativeContext, + gas_params: &LengthGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -36,12 +68,32 @@ pub fn native_length( debug_assert!(args.len() == 1); let r = pop_arg!(args, VectorRef); - let cost = native_gas(context.cost_table(), NativeCostIndex::LENGTH, 1); - NativeResult::map_partial_vm_result_one(cost, r.len(&ty_args[0])) + NativeResult::map_partial_vm_result_one(gas_params.base_cost, r.len(&ty_args[0])) +} + +pub fn make_native_length(gas_params: LengthGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_length(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun push_back + * + * gas cost: base_cost + legacy_unit_cost * max(1, size_of(val)) + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct PushBackGasParameters { + pub base_cost: u64, + pub legacy_unit_cost: u64, } pub fn native_push_back( - context: &mut NativeContext, + gas_params: &PushBackGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -50,16 +102,37 @@ pub fn native_push_back( let e = args.pop_back().unwrap(); let r = pop_arg!(args, VectorRef); - let cost = native_gas( - context.cost_table(), - NativeCostIndex::PUSH_BACK, - e.size().get() as usize, - ); + + let mut cost = gas_params.base_cost; + if gas_params.legacy_unit_cost != 0 { + cost += gas_params.legacy_unit_cost * u64::max(e.size().get(), 1) as u64; + } + NativeResult::map_partial_vm_result_empty(cost, r.push_back(e, &ty_args[0])) } +pub fn make_native_push_back(gas_params: PushBackGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_push_back(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun borrow + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct BorrowGasParameters { + pub base_cost: u64, +} + pub fn native_borrow( - context: &mut NativeContext, + gas_params: &BorrowGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -68,16 +141,35 @@ pub fn native_borrow( let idx = pop_arg!(args, u64) as usize; let r = pop_arg!(args, VectorRef); - let cost = native_gas(context.cost_table(), NativeCostIndex::BORROW, 1); NativeResult::map_partial_vm_result_one( - cost, + gas_params.base_cost, r.borrow_elem(idx, &ty_args[0]) .map_err(native_error_to_abort), ) } -pub fn native_pop( - context: &mut NativeContext, +pub fn make_native_borrow(gas_params: BorrowGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_borrow(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun pop + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct PopBackGasParameters { + pub base_cost: u64, +} + +pub fn native_pop_back( + gas_params: &PopBackGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -85,12 +177,34 @@ pub fn native_pop( debug_assert!(args.len() == 1); let r = pop_arg!(args, VectorRef); - let cost = native_gas(context.cost_table(), NativeCostIndex::POP_BACK, 1); - NativeResult::map_partial_vm_result_one(cost, r.pop(&ty_args[0]).map_err(native_error_to_abort)) + NativeResult::map_partial_vm_result_one( + gas_params.base_cost, + r.pop(&ty_args[0]).map_err(native_error_to_abort), + ) +} + +pub fn make_native_pop_back(gas_params: PopBackGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_pop_back(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun destroy_empty + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct DestroyEmptyGasParameters { + pub base_cost: u64, } pub fn native_destroy_empty( - context: &mut NativeContext, + gas_params: &DestroyEmptyGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -98,15 +212,31 @@ pub fn native_destroy_empty( debug_assert!(args.len() == 1); let v = pop_arg!(args, Vector); - let cost = native_gas(context.cost_table(), NativeCostIndex::DESTROY_EMPTY, 1); NativeResult::map_partial_vm_result_empty( - cost, + gas_params.base_cost, v.destroy_empty(&ty_args[0]).map_err(native_error_to_abort), ) } +pub fn make_native_destroy_empty(gas_params: DestroyEmptyGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_destroy_empty(&gas_params, context, ty_args, args) + }, + ) +} + +/*************************************************************************************************** + * native fun swap + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct SwapGasParameters { + pub base_cost: u64, +} + pub fn native_swap( - context: &mut NativeContext, + gas_params: &SwapGasParameters, + _context: &mut NativeContext, ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { @@ -116,14 +246,21 @@ pub fn native_swap( let idx2 = pop_arg!(args, u64) as usize; let idx1 = pop_arg!(args, u64) as usize; let r = pop_arg!(args, VectorRef); - let cost = native_gas(context.cost_table(), NativeCostIndex::SWAP, 1); NativeResult::map_partial_vm_result_empty( - cost, + gas_params.base_cost, r.swap(idx1, idx2, &ty_args[0]) .map_err(native_error_to_abort), ) } +pub fn make_native_swap(gas_params: SwapGasParameters) -> NativeFunction { + Arc::new( + move |context, ty_args, args| -> PartialVMResult { + native_swap(&gas_params, context, ty_args, args) + }, + ) +} + fn native_error_to_abort(err: PartialVMError) -> PartialVMError { let (major_status, sub_status_opt, message_opt, exec_state_opt, indices, offsets) = err.all_data(); @@ -145,3 +282,35 @@ fn native_error_to_abort(err: PartialVMError) -> PartialVMError { }; new_err.at_indices(indices).at_code_offsets(offsets) } + +/*************************************************************************************************** + * module + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct GasParameters { + pub empty: EmptyGasParameters, + pub length: LengthGasParameters, + pub push_back: PushBackGasParameters, + pub borrow: BorrowGasParameters, + pub pop_back: PopBackGasParameters, + pub destroy_empty: DestroyEmptyGasParameters, + pub swap: SwapGasParameters, +} + +pub fn make_all(gas_params: GasParameters) -> impl Iterator { + let natives = [ + ("empty", make_native_empty(gas_params.empty)), + ("length", make_native_length(gas_params.length)), + ("push_back", make_native_push_back(gas_params.push_back)), + ("borrow", make_native_borrow(gas_params.borrow.clone())), + ("borrow_mut", make_native_borrow(gas_params.borrow)), + ("pop_back", make_native_pop_back(gas_params.pop_back)), + ( + "destroy_empty", + make_native_destroy_empty(gas_params.destroy_empty), + ), + ("swap", make_native_swap(gas_params.swap)), + ]; + + make_module_natives(natives) +} diff --git a/language/move-stdlib/tests/move_unit_test.rs b/language/move-stdlib/tests/move_unit_test.rs index 187e244d83..4255c48980 100644 --- a/language/move-stdlib/tests/move_unit_test.rs +++ b/language/move-stdlib/tests/move_unit_test.rs @@ -4,12 +4,27 @@ use move_cli::base::test::{run_move_unit_tests, UnitTestResult}; use move_core_types::account_address::AccountAddress; -use move_stdlib::{natives::all_natives, path_in_crate}; +use move_stdlib::{ + natives::{all_natives, nursery_natives, GasParameters, NurseryGasParameters}, + path_in_crate, +}; use move_unit_test::UnitTestingConfig; use tempfile::tempdir; -fn run_tests_for_pkg(path_to_pkg: impl Into) { +fn run_tests_for_pkg(path_to_pkg: impl Into, include_nursery_natives: bool) { let pkg_path = path_in_crate(path_to_pkg); + + let mut natives = all_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + GasParameters::zeros(), + ); + if include_nursery_natives { + natives.extend(nursery_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + NurseryGasParameters::zeros(), + )) + } + let result = run_move_unit_tests( &pkg_path, move_package::BuildConfig { @@ -18,7 +33,7 @@ fn run_tests_for_pkg(path_to_pkg: impl Into) { ..Default::default() }, UnitTestingConfig::default_with_bound(Some(100_000)), - all_natives(AccountAddress::from_hex_literal("0x1").unwrap()), + natives, /* compute_coverage */ false, &mut std::io::stdout(), ) @@ -30,6 +45,6 @@ fn run_tests_for_pkg(path_to_pkg: impl Into) { #[test] fn move_unit_tests() { - run_tests_for_pkg("."); - run_tests_for_pkg("nursery"); + run_tests_for_pkg(".", false); + run_tests_for_pkg("nursery", true); } diff --git a/language/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs b/language/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs index 1d22c8a4e9..1287861869 100644 --- a/language/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs +++ b/language/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs @@ -12,7 +12,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::{BlankStorage, InMemoryStorage}; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -24,7 +24,6 @@ fn call_non_existent_module() { let mut sess = vm.new_session(&storage); let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); - let mut gas_status = GasStatus::new_unmetered(); let err = sess .execute_function_bypass_visibility( @@ -32,7 +31,7 @@ fn call_non_existent_module() { &fun_name, vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -59,7 +58,6 @@ fn call_non_existent_function() { let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); - let mut gas_status = GasStatus::new_unmetered(); let err = sess .execute_function_bypass_visibility( @@ -67,7 +65,7 @@ fn call_non_existent_function() { &fun_name, vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); diff --git a/language/move-vm/integration-tests/src/tests/bad_storage_tests.rs b/language/move-vm/integration-tests/src/tests/bad_storage_tests.rs index a1c94b4041..401a3ab245 100644 --- a/language/move-vm/integration-tests/src/tests/bad_storage_tests.rs +++ b/language/move-vm/integration-tests/src/tests/bad_storage_tests.rs @@ -15,7 +15,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::{DeltaStorage, InMemoryStorage}; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -86,11 +86,10 @@ fn test_malformed_resource() { let vm = MoveVM::new(move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), )) .unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - // Execute the first script to publish a resource Foo. let mut script_blob = vec![]; s1.serialize(&mut script_blob).unwrap(); @@ -99,7 +98,7 @@ fn test_malformed_resource() { script_blob, vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], - &mut gas_status, + &mut UnmeteredGasMeter, ) .map(|_| ()) .unwrap(); @@ -117,7 +116,7 @@ fn test_malformed_resource() { script_blob.clone(), vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], - &mut gas_status, + &mut UnmeteredGasMeter, ) .map(|_| ()) .unwrap(); @@ -144,7 +143,7 @@ fn test_malformed_resource() { script_blob, vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], - &mut gas_status, + &mut UnmeteredGasMeter, ) .map(|_| ()) .unwrap_err(); @@ -172,8 +171,6 @@ fn test_malformed_module() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - // Publish M and call M::foo. No errors should be thrown. { let mut storage = InMemoryStorage::new(); @@ -185,7 +182,7 @@ fn test_malformed_module() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); } @@ -211,7 +208,7 @@ fn test_malformed_module() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); assert_eq!(err.status_type(), StatusType::InvariantViolation); @@ -231,7 +228,6 @@ fn test_unverifiable_module() { let mut units = compile_units(&code).unwrap(); let m = as_module(units.pop().unwrap()); - let mut gas_status = GasStatus::new_unmetered(); let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); @@ -251,7 +247,7 @@ fn test_unverifiable_module() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); } @@ -276,7 +272,7 @@ fn test_unverifiable_module() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -308,8 +304,6 @@ fn test_missing_module_dependency() { let mut blob_n = vec![]; n.serialize(&mut blob_n).unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); @@ -328,7 +322,7 @@ fn test_missing_module_dependency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); } @@ -348,7 +342,7 @@ fn test_missing_module_dependency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -380,8 +374,6 @@ fn test_malformed_module_denpency() { let mut blob_n = vec![]; n.serialize(&mut blob_n).unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); @@ -400,7 +392,7 @@ fn test_malformed_module_denpency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); } @@ -426,7 +418,7 @@ fn test_malformed_module_denpency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -456,8 +448,6 @@ fn test_unverifiable_module_dependency() { let mut blob_n = vec![]; n.serialize(&mut blob_n).unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); @@ -479,7 +469,7 @@ fn test_unverifiable_module_dependency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); } @@ -505,7 +495,7 @@ fn test_unverifiable_module_dependency() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -549,7 +539,6 @@ const LIST_OF_ERROR_CODES: &[StatusCode] = &[ #[test] fn test_storage_returns_bogus_error_when_loading_module() { - let mut gas_status = GasStatus::new_unmetered(); let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); @@ -566,7 +555,7 @@ fn test_storage_returns_bogus_error_when_loading_module() { &fun_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); @@ -576,8 +565,6 @@ fn test_storage_returns_bogus_error_when_loading_module() { #[test] fn test_storage_returns_bogus_error_when_loading_resource() { - let mut gas_status = GasStatus::new_unmetered(); - let code = r#" address std { module signer { @@ -626,6 +613,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { let vm = MoveVM::new(move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), )) .unwrap(); let mut sess = vm.new_session(&storage); @@ -635,7 +623,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { &foo_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); @@ -645,7 +633,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { &bar_name, vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_err(); diff --git a/language/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs b/language/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs index 205cc79f70..89850c4cfa 100644 --- a/language/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs +++ b/language/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs @@ -9,7 +9,6 @@ use move_binary_format::errors::VMResult; use move_core_types::{ account_address::AccountAddress, effects::{ChangeSet, Event}, - gas_schedule::GasAlgebra, identifier::Identifier, language_storage::ModuleId, value::{serialize_values, MoveValue}, @@ -17,7 +16,7 @@ use move_core_types::{ }; use move_vm_runtime::{move_vm::MoveVM, session::SerializedReturnValues}; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); const TEST_MODULE_ID: &str = "M"; @@ -39,7 +38,6 @@ fn fail_arg_deserialize() { for value in values { for name in FUN_NAMES { let err = run(&mod_code, name, value.clone()) - .1 .map(|_| ()) .expect_err("Should have failed to deserialize non-u64 type to u64"); assert_eq!( @@ -54,7 +52,7 @@ fn fail_arg_deserialize() { #[test] fn mutref_output_success() { let mod_code = setup_module(); - let (_gas_used, result) = run(&mod_code, USE_MUTREF_LABEL, MoveValue::U64(1)); + let result = run(&mod_code, USE_MUTREF_LABEL, MoveValue::U64(1)); let (_, _, ret_values) = result.unwrap(); assert_eq!(1, ret_values.mutable_reference_outputs.len()); let parsed = parse_u64_arg(&ret_values.mutable_reference_outputs.first().unwrap().1); @@ -84,32 +82,26 @@ fn run( module: &ModuleCode, fun_name: &str, arg_val0: MoveValue, -) -> ( - /* gas used */ u64, - VMResult<(ChangeSet, Vec, SerializedReturnValues)>, -) { +) -> VMResult<(ChangeSet, Vec, SerializedReturnValues)> { let module_id = &module.0; let modules = vec![module.clone()]; let (vm, storage) = setup_vm(&modules); let mut session = vm.new_session(&storage); let fun_name = Identifier::new(fun_name).unwrap(); - let mut gas_status = GasStatus::new_unmetered(); - let gas_start = gas_status.remaining_gas().get(); - let res = session + + session .execute_function_bypass_visibility( module_id, &fun_name, vec![], serialize_values(&vec![arg_val0]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .and_then(|ret_values| { let (change_set, events) = session.finish()?; Ok((change_set, events, ret_values)) - }); - let gas_used = gas_start - gas_status.remaining_gas().get(); - (gas_used, res) + }) } type ModuleCode = (ModuleId, String); diff --git a/language/move-vm/integration-tests/src/tests/function_arg_tests.rs b/language/move-vm/integration-tests/src/tests/function_arg_tests.rs index 52fbb910e5..a882cea324 100644 --- a/language/move-vm/integration-tests/src/tests/function_arg_tests.rs +++ b/language/move-vm/integration-tests/src/tests/function_arg_tests.rs @@ -13,7 +13,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -60,14 +60,19 @@ fn run( let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); - let mut gas_status = GasStatus::new_unmetered(); let args: Vec<_> = args .into_iter() .map(|val| val.simple_serialize().unwrap()) .collect(); - sess.execute_function_bypass_visibility(&module_id, &fun_name, ty_args, args, &mut gas_status)?; + sess.execute_function_bypass_visibility( + &module_id, + &fun_name, + ty_args, + args, + &mut UnmeteredGasMeter, + )?; Ok(()) } diff --git a/language/move-vm/integration-tests/src/tests/loader_tests.rs b/language/move-vm/integration-tests/src/tests/loader_tests.rs index 9b5b0a7ab6..018c6b141b 100644 --- a/language/move-vm/integration-tests/src/tests/loader_tests.rs +++ b/language/move-vm/integration-tests/src/tests/loader_tests.rs @@ -11,7 +11,8 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; + use std::{path::PathBuf, sync::Arc, thread}; const WORKING_ACCOUNT: AccountAddress = @@ -56,14 +57,14 @@ impl Adapter { fn publish_modules(&mut self, modules: Vec) { let mut session = self.vm.new_session(&self.store); - let mut gas_status = GasStatus::new_unmetered(); + for module in modules { let mut binary = vec![]; module .serialize(&mut binary) .unwrap_or_else(|_| panic!("failure in module serialization: {:#?}", module)); session - .publish_module(binary, WORKING_ACCOUNT, &mut gas_status) + .publish_module(binary, WORKING_ACCOUNT, &mut UnmeteredGasMeter) .unwrap_or_else(|_| panic!("failure publishing module: {:#?}", module)); } let (changeset, _) = session.finish().expect("failure getting write set"); @@ -85,7 +86,6 @@ impl Adapter { let vm = self.vm.clone(); let data_store = self.store.clone(); children.push(thread::spawn(move || { - let mut gas_status = GasStatus::new_unmetered(); let mut session = vm.new_session(&data_store); session .execute_function_bypass_visibility( @@ -93,7 +93,7 @@ impl Adapter { &name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_or_else(|_| { panic!("Failure executing {:?}::{:?}", module_id, name) @@ -107,7 +107,6 @@ impl Adapter { } fn call_function(&self, module: &ModuleId, name: &IdentStr) { - let mut gas_status = GasStatus::new_unmetered(); let mut session = self.vm.new_session(&self.store); session .execute_function_bypass_visibility( @@ -115,7 +114,7 @@ impl Adapter { name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap_or_else(|_| panic!("Failure executing {:?}::{:?}", module, name)); } diff --git a/language/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs b/language/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs index 661b7cab08..ad9d9188d6 100644 --- a/language/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs +++ b/language/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs @@ -11,7 +11,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -46,8 +46,6 @@ fn mutated_accounts() { let vm = MoveVM::new(vec![]).unwrap(); let mut sess = vm.new_session(&storage); - let mut gas_status = GasStatus::new_unmetered(); - let publish = Identifier::new("publish").unwrap(); let flip = Identifier::new("flip").unwrap(); let get = Identifier::new("get").unwrap(); @@ -59,7 +57,7 @@ fn mutated_accounts() { &publish, vec![], serialize_values(&vec![MoveValue::Signer(account1)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); @@ -73,7 +71,7 @@ fn mutated_accounts() { &get, vec![], serialize_values(&vec![MoveValue::Address(account1)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); @@ -84,7 +82,7 @@ fn mutated_accounts() { &flip, vec![], serialize_values(&vec![MoveValue::Address(account1)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); assert_eq!(sess.num_mutated_accounts(&TEST_ADDR), 2); @@ -98,7 +96,7 @@ fn mutated_accounts() { &get, vec![], serialize_values(&vec![MoveValue::Address(account1)]), - &mut gas_status, + &mut UnmeteredGasMeter, ) .unwrap(); diff --git a/language/move-vm/integration-tests/src/tests/return_value_tests.rs b/language/move-vm/integration-tests/src/tests/return_value_tests.rs index 230541c48a..841054cb8d 100644 --- a/language/move-vm/integration-tests/src/tests/return_value_tests.rs +++ b/language/move-vm/integration-tests/src/tests/return_value_tests.rs @@ -12,7 +12,7 @@ use move_core_types::{ }; use move_vm_runtime::{move_vm::MoveVM, session::SerializedReturnValues}; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -51,7 +51,6 @@ fn run( let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); - let mut gas_status = GasStatus::new_unmetered(); let args: Vec<_> = args .into_iter() @@ -66,7 +65,7 @@ fn run( &fun_name, ty_args, args, - &mut gas_status, + &mut UnmeteredGasMeter, )?; Ok(return_values diff --git a/language/move-vm/runtime/src/interpreter.rs b/language/move-vm/runtime/src/interpreter.rs index d79722992d..bcd4942e09 100644 --- a/language/move-vm/runtime/src/interpreter.rs +++ b/language/move-vm/runtime/src/interpreter.rs @@ -20,7 +20,7 @@ use move_core_types::{ }; use move_vm_types::{ data_store::DataStore, - gas_schedule::GasStatus, + gas::GasMeter, loaded_data::runtime_types::Type, values::{ self, GlobalValue, IntegerValue, Locals, Reference, Struct, StructRef, VMValueCast, Value, @@ -76,7 +76,7 @@ impl Interpreter { ty_args: Vec, args: Vec, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, loader: &Loader, ) -> VMResult> { @@ -84,7 +84,7 @@ impl Interpreter { // setup of the function. let mut interp = Self::new(); interp.execute( - loader, data_store, gas_status, extensions, function, ty_args, args, + loader, data_store, gas_meter, extensions, function, ty_args, args, ) } @@ -102,7 +102,7 @@ impl Interpreter { &mut self, loader: &Loader, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, @@ -111,7 +111,7 @@ impl Interpreter { // No unwinding of the call stack and value stack need to be done here -- the context will // take care of that. self.execute_main( - loader, data_store, gas_status, extensions, function, ty_args, args, + loader, data_store, gas_meter, extensions, function, ty_args, args, ) } @@ -127,7 +127,7 @@ impl Interpreter { &mut self, loader: &Loader, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, @@ -144,7 +144,7 @@ impl Interpreter { loop { let resolver = current_frame.resolver(loader); let exit_code = current_frame //self - .execute_code(&resolver, self, data_store, gas_status) + .execute_code(&resolver, self, data_store, gas_meter) .map_err(|err| self.maybe_core_dump(err, ¤t_frame))?; match exit_code { ExitCode::Return => { @@ -156,21 +156,22 @@ impl Interpreter { } } ExitCode::Call(fh_idx) => { - gas_status + gas_meter .charge_instr_with_size(Opcodes::CALL, AbstractMemorySize::new(1)) .map_err(|e| set_err_info!(current_frame, e))?; let func = resolver.function_from_handle(fh_idx); - gas_status + gas_meter .charge_instr_with_size( Opcodes::CALL, AbstractMemorySize::new(func.arg_count() as GasCarrier), ) .map_err(|e| set_err_info!(current_frame, e))?; + if func.is_native() { self.call_native( &resolver, data_store, - gas_status, + gas_meter, extensions, func, vec![], @@ -190,7 +191,7 @@ impl Interpreter { } ExitCode::CallGeneric(idx) => { let arity = resolver.type_params_count(idx); - gas_status + gas_meter .charge_instr_with_size( Opcodes::CALL_GENERIC, AbstractMemorySize::new((arity + 1) as GasCarrier), @@ -200,7 +201,7 @@ impl Interpreter { .instantiate_generic_function(idx, current_frame.ty_args()) .map_err(|e| set_err_info!(current_frame, e))?; let func = resolver.function_from_instantiation(idx); - gas_status + gas_meter .charge_instr_with_size( Opcodes::CALL_GENERIC, AbstractMemorySize::new(func.arg_count() as GasCarrier), @@ -208,7 +209,7 @@ impl Interpreter { .map_err(|e| set_err_info!(current_frame, e))?; if func.is_native() { self.call_native( - &resolver, data_store, gas_status, extensions, func, ty_args, + &resolver, data_store, gas_meter, extensions, func, ty_args, )?; current_frame.pc += 1; // advance past the Call instruction in the caller continue; @@ -251,7 +252,7 @@ impl Interpreter { &mut self, resolver: &Resolver, data_store: &mut dyn DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, @@ -260,7 +261,7 @@ impl Interpreter { self.call_native_impl( resolver, data_store, - gas_status, + gas_meter, extensions, function.clone(), ty_args, @@ -281,21 +282,22 @@ impl Interpreter { &mut self, resolver: &Resolver, data_store: &mut dyn DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, ) -> PartialVMResult<()> { - let mut arguments = VecDeque::new(); + let mut args = VecDeque::new(); let expected_args = function.arg_count(); for _ in 0..expected_args { - arguments.push_front(self.operand_stack.pop()?); + args.push_front(self.operand_stack.pop()?); } - let mut native_context = - NativeContext::new(self, data_store, gas_status, resolver, extensions); + let mut native_context = NativeContext::new(self, data_store, resolver, extensions); let native_function = function.get_native()?; - let result = native_function(&mut native_context, ty_args, arguments)?; - gas_status.deduct_gas(result.cost)?; + + let result = native_function(&mut native_context, ty_args, args)?; + gas_meter.charge_in_native_unit(result.cost)?; + let return_values = result .result .map_err(|code| PartialVMError::new(StatusCode::ABORTED).with_sub_status(code))?; @@ -720,9 +722,9 @@ impl Frame { resolver: &Resolver, interpreter: &mut Interpreter, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult { - self.execute_code_impl(resolver, interpreter, data_store, gas_status) + self.execute_code_impl(resolver, interpreter, data_store, gas_meter) .map_err(|e| { e.at_code_offset(self.function.index(), self.pc) .finish(self.location()) @@ -734,7 +736,7 @@ impl Frame { resolver: &Resolver, interpreter: &mut Interpreter, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> PartialVMResult { let code = self.function.code(); loop { @@ -758,47 +760,47 @@ impl Frame { match instruction { Bytecode::Pop => { - gas_status.charge_instr(Opcodes::POP)?; + gas_meter.charge_instr(Opcodes::POP)?; interpreter.operand_stack.pop()?; } Bytecode::Ret => { - gas_status.charge_instr(Opcodes::RET)?; + gas_meter.charge_instr(Opcodes::RET)?; return Ok(ExitCode::Return); } Bytecode::BrTrue(offset) => { - gas_status.charge_instr(Opcodes::BR_TRUE)?; + gas_meter.charge_instr(Opcodes::BR_TRUE)?; if interpreter.operand_stack.pop_as::()? { self.pc = *offset; break; } } Bytecode::BrFalse(offset) => { - gas_status.charge_instr(Opcodes::BR_FALSE)?; + gas_meter.charge_instr(Opcodes::BR_FALSE)?; if !interpreter.operand_stack.pop_as::()? { self.pc = *offset; break; } } Bytecode::Branch(offset) => { - gas_status.charge_instr(Opcodes::BRANCH)?; + gas_meter.charge_instr(Opcodes::BRANCH)?; self.pc = *offset; break; } Bytecode::LdU8(int_const) => { - gas_status.charge_instr(Opcodes::LD_U8)?; + gas_meter.charge_instr(Opcodes::LD_U8)?; interpreter.operand_stack.push(Value::u8(*int_const))?; } Bytecode::LdU64(int_const) => { - gas_status.charge_instr(Opcodes::LD_U64)?; + gas_meter.charge_instr(Opcodes::LD_U64)?; interpreter.operand_stack.push(Value::u64(*int_const))?; } Bytecode::LdU128(int_const) => { - gas_status.charge_instr(Opcodes::LD_U128)?; + gas_meter.charge_instr(Opcodes::LD_U128)?; interpreter.operand_stack.push(Value::u128(*int_const))?; } Bytecode::LdConst(idx) => { let constant = resolver.constant_at(*idx); - gas_status.charge_instr_with_size( + gas_meter.charge_instr_with_size( Opcodes::LD_CONST, AbstractMemorySize::new(constant.data.len() as GasCarrier), )?; @@ -813,28 +815,27 @@ impl Frame { )? } Bytecode::LdTrue => { - gas_status.charge_instr(Opcodes::LD_TRUE)?; + gas_meter.charge_instr(Opcodes::LD_TRUE)?; interpreter.operand_stack.push(Value::bool(true))?; } Bytecode::LdFalse => { - gas_status.charge_instr(Opcodes::LD_FALSE)?; + gas_meter.charge_instr(Opcodes::LD_FALSE)?; interpreter.operand_stack.push(Value::bool(false))?; } Bytecode::CopyLoc(idx) => { let local = self.locals.copy_loc(*idx as usize)?; - gas_status.charge_instr_with_size(Opcodes::COPY_LOC, local.size())?; + gas_meter.charge_instr_with_size(Opcodes::COPY_LOC, local.size())?; interpreter.operand_stack.push(local)?; } Bytecode::MoveLoc(idx) => { let local = self.locals.move_loc(*idx as usize)?; - gas_status.charge_instr_with_size(Opcodes::MOVE_LOC, local.size())?; + gas_meter.charge_instr_with_size(Opcodes::MOVE_LOC, local.size())?; interpreter.operand_stack.push(local)?; } Bytecode::StLoc(idx) => { let value_to_store = interpreter.operand_stack.pop()?; - gas_status - .charge_instr_with_size(Opcodes::ST_LOC, value_to_store.size())?; + gas_meter.charge_instr_with_size(Opcodes::ST_LOC, value_to_store.size())?; self.locals.store_loc(*idx as usize, value_to_store)?; } Bytecode::Call(idx) => { @@ -848,7 +849,7 @@ impl Frame { Bytecode::MutBorrowLoc(_) => Opcodes::MUT_BORROW_LOC, _ => Opcodes::IMM_BORROW_LOC, }; - gas_status.charge_instr(opcode)?; + gas_meter.charge_instr(opcode)?; interpreter .operand_stack .push(self.locals.borrow_loc(*idx as usize)?)?; @@ -858,7 +859,7 @@ impl Frame { Bytecode::MutBorrowField(_) => Opcodes::MUT_BORROW_FIELD, _ => Opcodes::IMM_BORROW_FIELD, }; - gas_status.charge_instr(opcode)?; + gas_meter.charge_instr(opcode)?; let reference = interpreter.operand_stack.pop_as::()?; let offset = resolver.field_offset(*fh_idx); @@ -871,7 +872,7 @@ impl Frame { Bytecode::MutBorrowField(_) => Opcodes::MUT_BORROW_FIELD_GENERIC, _ => Opcodes::IMM_BORROW_FIELD_GENERIC, }; - gas_status.charge_instr(opcode)?; + gas_meter.charge_instr(opcode)?; let reference = interpreter.operand_stack.pop_as::()?; let offset = resolver.field_instantiation_offset(*fi_idx); @@ -885,7 +886,7 @@ impl Frame { AbstractMemorySize::new(GasCarrier::from(field_count)), |acc, v| acc.add(v.size()), ); - gas_status.charge_instr_with_size(Opcodes::PACK, size)?; + gas_meter.charge_instr_with_size(Opcodes::PACK, size)?; interpreter .operand_stack .push(Value::struct_(Struct::pack(args)))?; @@ -897,7 +898,7 @@ impl Frame { AbstractMemorySize::new(GasCarrier::from(field_count)), |acc, v| acc.add(v.size()), ); - gas_status.charge_instr_with_size(Opcodes::PACK_GENERIC, size)?; + gas_meter.charge_instr_with_size(Opcodes::PACK_GENERIC, size)?; interpreter .operand_stack .push(Value::struct_(Struct::pack(args)))?; @@ -905,7 +906,7 @@ impl Frame { Bytecode::Unpack(sd_idx) => { let field_count = resolver.field_count(*sd_idx); let struct_ = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr_with_size( + gas_meter.charge_instr_with_size( Opcodes::UNPACK, AbstractMemorySize::new(GasCarrier::from(field_count)), )?; @@ -913,14 +914,14 @@ impl Frame { // questionable. However, if we don't have it in the loop we could wind up // doing a fair bit of work before charging for it. for value in struct_.unpack()? { - gas_status.charge_instr_with_size(Opcodes::UNPACK, value.size())?; + gas_meter.charge_instr_with_size(Opcodes::UNPACK, value.size())?; interpreter.operand_stack.push(value)?; } } Bytecode::UnpackGeneric(si_idx) => { let field_count = resolver.field_instantiation_count(*si_idx); let struct_ = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr_with_size( + gas_meter.charge_instr_with_size( Opcodes::UNPACK_GENERIC, AbstractMemorySize::new(GasCarrier::from(field_count)), )?; @@ -928,7 +929,7 @@ impl Frame { // questionable. However, if we don't have it in the loop we could wind up // doing a fair bit of work before charging for it. for value in struct_.unpack()? { - gas_status + gas_meter .charge_instr_with_size(Opcodes::UNPACK_GENERIC, value.size())?; interpreter.operand_stack.push(value)?; } @@ -936,31 +937,31 @@ impl Frame { Bytecode::ReadRef => { let reference = interpreter.operand_stack.pop_as::()?; let value = reference.read_ref()?; - gas_status.charge_instr_with_size(Opcodes::READ_REF, value.size())?; + gas_meter.charge_instr_with_size(Opcodes::READ_REF, value.size())?; interpreter.operand_stack.push(value)?; } Bytecode::WriteRef => { let reference = interpreter.operand_stack.pop_as::()?; let value = interpreter.operand_stack.pop()?; - gas_status.charge_instr_with_size(Opcodes::WRITE_REF, value.size())?; + gas_meter.charge_instr_with_size(Opcodes::WRITE_REF, value.size())?; reference.write_ref(value)?; } Bytecode::CastU8 => { - gas_status.charge_instr(Opcodes::CAST_U8)?; + gas_meter.charge_instr(Opcodes::CAST_U8)?; let integer_value = interpreter.operand_stack.pop_as::()?; interpreter .operand_stack .push(Value::u8(integer_value.cast_u8()?))?; } Bytecode::CastU64 => { - gas_status.charge_instr(Opcodes::CAST_U64)?; + gas_meter.charge_instr(Opcodes::CAST_U64)?; let integer_value = interpreter.operand_stack.pop_as::()?; interpreter .operand_stack .push(Value::u64(integer_value.cast_u64()?))?; } Bytecode::CastU128 => { - gas_status.charge_instr(Opcodes::CAST_U128)?; + gas_meter.charge_instr(Opcodes::CAST_U128)?; let integer_value = interpreter.operand_stack.pop_as::()?; interpreter .operand_stack @@ -968,39 +969,39 @@ impl Frame { } // Arithmetic Operations Bytecode::Add => { - gas_status.charge_instr(Opcodes::ADD)?; + gas_meter.charge_instr(Opcodes::ADD)?; interpreter.binop_int(IntegerValue::add_checked)? } Bytecode::Sub => { - gas_status.charge_instr(Opcodes::SUB)?; + gas_meter.charge_instr(Opcodes::SUB)?; interpreter.binop_int(IntegerValue::sub_checked)? } Bytecode::Mul => { - gas_status.charge_instr(Opcodes::MUL)?; + gas_meter.charge_instr(Opcodes::MUL)?; interpreter.binop_int(IntegerValue::mul_checked)? } Bytecode::Mod => { - gas_status.charge_instr(Opcodes::MOD)?; + gas_meter.charge_instr(Opcodes::MOD)?; interpreter.binop_int(IntegerValue::rem_checked)? } Bytecode::Div => { - gas_status.charge_instr(Opcodes::DIV)?; + gas_meter.charge_instr(Opcodes::DIV)?; interpreter.binop_int(IntegerValue::div_checked)? } Bytecode::BitOr => { - gas_status.charge_instr(Opcodes::BIT_OR)?; + gas_meter.charge_instr(Opcodes::BIT_OR)?; interpreter.binop_int(IntegerValue::bit_or)? } Bytecode::BitAnd => { - gas_status.charge_instr(Opcodes::BIT_AND)?; + gas_meter.charge_instr(Opcodes::BIT_AND)?; interpreter.binop_int(IntegerValue::bit_and)? } Bytecode::Xor => { - gas_status.charge_instr(Opcodes::XOR)?; + gas_meter.charge_instr(Opcodes::XOR)?; interpreter.binop_int(IntegerValue::bit_xor)? } Bytecode::Shl => { - gas_status.charge_instr(Opcodes::SHL)?; + gas_meter.charge_instr(Opcodes::SHL)?; let rhs = interpreter.operand_stack.pop_as::()?; let lhs = interpreter.operand_stack.pop_as::()?; interpreter @@ -1008,7 +1009,7 @@ impl Frame { .push(lhs.shl_checked(rhs)?.into_value())?; } Bytecode::Shr => { - gas_status.charge_instr(Opcodes::SHR)?; + gas_meter.charge_instr(Opcodes::SHR)?; let rhs = interpreter.operand_stack.pop_as::()?; let lhs = interpreter.operand_stack.pop_as::()?; interpreter @@ -1016,31 +1017,31 @@ impl Frame { .push(lhs.shr_checked(rhs)?.into_value())?; } Bytecode::Or => { - gas_status.charge_instr(Opcodes::OR)?; + gas_meter.charge_instr(Opcodes::OR)?; interpreter.binop_bool(|l, r| Ok(l || r))? } Bytecode::And => { - gas_status.charge_instr(Opcodes::AND)?; + gas_meter.charge_instr(Opcodes::AND)?; interpreter.binop_bool(|l, r| Ok(l && r))? } Bytecode::Lt => { - gas_status.charge_instr(Opcodes::LT)?; + gas_meter.charge_instr(Opcodes::LT)?; interpreter.binop_bool(IntegerValue::lt)? } Bytecode::Gt => { - gas_status.charge_instr(Opcodes::GT)?; + gas_meter.charge_instr(Opcodes::GT)?; interpreter.binop_bool(IntegerValue::gt)? } Bytecode::Le => { - gas_status.charge_instr(Opcodes::LE)?; + gas_meter.charge_instr(Opcodes::LE)?; interpreter.binop_bool(IntegerValue::le)? } Bytecode::Ge => { - gas_status.charge_instr(Opcodes::GE)?; + gas_meter.charge_instr(Opcodes::GE)?; interpreter.binop_bool(IntegerValue::ge)? } Bytecode::Abort => { - gas_status.charge_instr(Opcodes::ABORT)?; + gas_meter.charge_instr(Opcodes::ABORT)?; let error_code = interpreter.operand_stack.pop_as::()?; let error = PartialVMError::new(StatusCode::ABORTED) .with_sub_status(error_code) @@ -1058,7 +1059,7 @@ impl Frame { Bytecode::Eq => { let lhs = interpreter.operand_stack.pop()?; let rhs = interpreter.operand_stack.pop()?; - gas_status + gas_meter .charge_instr_with_size(Opcodes::EQ, lhs.size().add(rhs.size()))?; interpreter .operand_stack @@ -1067,7 +1068,7 @@ impl Frame { Bytecode::Neq => { let lhs = interpreter.operand_stack.pop()?; let rhs = interpreter.operand_stack.pop()?; - gas_status + gas_meter .charge_instr_with_size(Opcodes::NEQ, lhs.size().add(rhs.size()))?; interpreter .operand_stack @@ -1077,27 +1078,27 @@ impl Frame { let addr = interpreter.operand_stack.pop_as::()?; let ty = resolver.get_struct_type(*sd_idx); let size = interpreter.borrow_global(data_store, addr, &ty)?; - gas_status.charge_instr_with_size(Opcodes::MUT_BORROW_GLOBAL, size)?; + gas_meter.charge_instr_with_size(Opcodes::MUT_BORROW_GLOBAL, size)?; } Bytecode::MutBorrowGlobalGeneric(si_idx) | Bytecode::ImmBorrowGlobalGeneric(si_idx) => { let addr = interpreter.operand_stack.pop_as::()?; let ty = resolver.instantiate_generic_type(*si_idx, self.ty_args())?; let size = interpreter.borrow_global(data_store, addr, &ty)?; - gas_status + gas_meter .charge_instr_with_size(Opcodes::MUT_BORROW_GLOBAL_GENERIC, size)?; } Bytecode::Exists(sd_idx) => { let addr = interpreter.operand_stack.pop_as::()?; let ty = resolver.get_struct_type(*sd_idx); let size = interpreter.exists(data_store, addr, &ty)?; - gas_status.charge_instr_with_size(Opcodes::EXISTS, size)?; + gas_meter.charge_instr_with_size(Opcodes::EXISTS, size)?; } Bytecode::ExistsGeneric(si_idx) => { let addr = interpreter.operand_stack.pop_as::()?; let ty = resolver.instantiate_generic_type(*si_idx, self.ty_args())?; let size = interpreter.exists(data_store, addr, &ty)?; - gas_status.charge_instr_with_size(Opcodes::EXISTS_GENERIC, size)?; + gas_meter.charge_instr_with_size(Opcodes::EXISTS_GENERIC, size)?; } Bytecode::MoveFrom(sd_idx) => { let addr = interpreter.operand_stack.pop_as::()?; @@ -1105,7 +1106,7 @@ impl Frame { let size = interpreter.move_from(data_store, addr, &ty)?; // TODO: Have this calculate before pulling in the data based upon // the size of the data that we are about to read in. - gas_status.charge_instr_with_size(Opcodes::MOVE_FROM, size)?; + gas_meter.charge_instr_with_size(Opcodes::MOVE_FROM, size)?; } Bytecode::MoveFromGeneric(si_idx) => { let addr = interpreter.operand_stack.pop_as::()?; @@ -1113,7 +1114,7 @@ impl Frame { let size = interpreter.move_from(data_store, addr, &ty)?; // TODO: Have this calculate before pulling in the data based upon // the size of the data that we are about to read in. - gas_status.charge_instr_with_size(Opcodes::MOVE_FROM_GENERIC, size)?; + gas_meter.charge_instr_with_size(Opcodes::MOVE_FROM_GENERIC, size)?; } Bytecode::MoveTo(sd_idx) => { let resource = interpreter.operand_stack.pop()?; @@ -1126,7 +1127,7 @@ impl Frame { let ty = resolver.get_struct_type(*sd_idx); // REVIEW: Can we simplify Interpreter::move_to? let size = interpreter.move_to(data_store, addr, &ty, resource)?; - gas_status.charge_instr_with_size(Opcodes::MOVE_TO, size)?; + gas_meter.charge_instr_with_size(Opcodes::MOVE_TO, size)?; } Bytecode::MoveToGeneric(si_idx) => { let resource = interpreter.operand_stack.pop()?; @@ -1138,25 +1139,25 @@ impl Frame { .value_as::()?; let ty = resolver.instantiate_generic_type(*si_idx, self.ty_args())?; let size = interpreter.move_to(data_store, addr, &ty, resource)?; - gas_status.charge_instr_with_size(Opcodes::MOVE_TO_GENERIC, size)?; + gas_meter.charge_instr_with_size(Opcodes::MOVE_TO_GENERIC, size)?; } Bytecode::FreezeRef => { - gas_status.charge_instr(Opcodes::FREEZE_REF)?; + gas_meter.charge_instr(Opcodes::FREEZE_REF)?; // FreezeRef should just be a null op as we don't distinguish between mut // and immut ref at runtime. } Bytecode::Not => { - gas_status.charge_instr(Opcodes::NOT)?; + gas_meter.charge_instr(Opcodes::NOT)?; let value = !interpreter.operand_stack.pop_as::()?; interpreter.operand_stack.push(Value::bool(value))?; } Bytecode::Nop => { - gas_status.charge_instr(Opcodes::NOP)?; + gas_meter.charge_instr(Opcodes::NOP)?; } Bytecode::VecPack(si, num) => { let elements = interpreter.operand_stack.popn(*num as u16)?; let size = AbstractMemorySize::new(*num); - gas_status.charge_instr_with_size(Opcodes::VEC_PACK, size)?; + gas_meter.charge_instr_with_size(Opcodes::VEC_PACK, size)?; let value = Vector::pack( &resolver.instantiate_single_type(*si, self.ty_args())?, elements, @@ -1165,7 +1166,7 @@ impl Frame { } Bytecode::VecLen(si) => { let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr(Opcodes::VEC_LEN)?; + gas_meter.charge_instr(Opcodes::VEC_LEN)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; let value = vec_ref.len(vec_ty_arg)?; interpreter.operand_stack.push(value)?; @@ -1173,7 +1174,7 @@ impl Frame { Bytecode::VecImmBorrow(si) => { let idx = interpreter.operand_stack.pop_as::()? as usize; let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr(Opcodes::VEC_IMM_BORROW)?; + gas_meter.charge_instr(Opcodes::VEC_IMM_BORROW)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; let value = vec_ref.borrow_elem(idx, vec_ty_arg)?; interpreter.operand_stack.push(value)?; @@ -1181,7 +1182,7 @@ impl Frame { Bytecode::VecMutBorrow(si) => { let idx = interpreter.operand_stack.pop_as::()? as usize; let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr(Opcodes::VEC_MUT_BORROW)?; + gas_meter.charge_instr(Opcodes::VEC_MUT_BORROW)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; let value = vec_ref.borrow_elem(idx, vec_ty_arg)?; interpreter.operand_stack.push(value)?; @@ -1189,13 +1190,13 @@ impl Frame { Bytecode::VecPushBack(si) => { let elem = interpreter.operand_stack.pop()?; let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr_with_size(Opcodes::VEC_PUSH_BACK, elem.size())?; + gas_meter.charge_instr_with_size(Opcodes::VEC_PUSH_BACK, elem.size())?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; vec_ref.push_back(elem, vec_ty_arg)?; } Bytecode::VecPopBack(si) => { let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr(Opcodes::VEC_POP_BACK)?; + gas_meter.charge_instr(Opcodes::VEC_POP_BACK)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; let value = vec_ref.pop(vec_ty_arg)?; interpreter.operand_stack.push(value)?; @@ -1203,7 +1204,7 @@ impl Frame { Bytecode::VecUnpack(si, num) => { let vec_val = interpreter.operand_stack.pop_as::()?; let size = AbstractMemorySize::new(*num); - gas_status.charge_instr_with_size(Opcodes::VEC_UNPACK, size)?; + gas_meter.charge_instr_with_size(Opcodes::VEC_UNPACK, size)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; let elements = vec_val.unpack(vec_ty_arg, *num)?; for value in elements { @@ -1214,7 +1215,7 @@ impl Frame { let idx2 = interpreter.operand_stack.pop_as::()? as usize; let idx1 = interpreter.operand_stack.pop_as::()? as usize; let vec_ref = interpreter.operand_stack.pop_as::()?; - gas_status.charge_instr(Opcodes::VEC_SWAP)?; + gas_meter.charge_instr(Opcodes::VEC_SWAP)?; let vec_ty_arg = &resolver.instantiate_single_type(*si, self.ty_args())?; vec_ref.swap(idx1, idx2, vec_ty_arg)?; } diff --git a/language/move-vm/runtime/src/loader.rs b/language/move-vm/runtime/src/loader.rs index e7028b0a25..6e582e8c61 100644 --- a/language/move-vm/runtime/src/loader.rs +++ b/language/move-vm/runtime/src/loader.rs @@ -4,7 +4,7 @@ use crate::{ logging::expect_no_verification_errors, - native_functions::{NativeFunction, NativeFunctions}, + native_functions::{NativeFunction, NativeFunctions, UnboxedNativeFunction}, session::LoadedFunctionInstantiation, }; use move_binary_format::{ @@ -1971,8 +1971,8 @@ impl Function { self.native.is_some() } - pub(crate) fn get_native(&self) -> PartialVMResult { - self.native.ok_or_else(|| { + pub(crate) fn get_native(&self) -> PartialVMResult<&UnboxedNativeFunction> { + self.native.as_deref().map(|f| &*f).ok_or_else(|| { PartialVMError::new(StatusCode::UNREACHABLE) .with_message("Missing Native Function".to_string()) }) diff --git a/language/move-vm/runtime/src/native_functions.rs b/language/move-vm/runtime/src/native_functions.rs index bc383f430c..a0491b5e89 100644 --- a/language/move-vm/runtime/src/native_functions.rs +++ b/language/move-vm/runtime/src/native_functions.rs @@ -8,23 +8,27 @@ use crate::{ use move_binary_format::errors::{ExecutionState, PartialVMError, PartialVMResult}; use move_core_types::{ account_address::AccountAddress, - gas_schedule::CostTable, identifier::Identifier, language_storage::TypeTag, value::MoveTypeLayout, vm_status::{StatusCode, StatusType}, }; use move_vm_types::{ - data_store::DataStore, gas_schedule::GasStatus, loaded_data::runtime_types::Type, - natives::function::NativeResult, values::Value, + data_store::DataStore, loaded_data::runtime_types::Type, natives::function::NativeResult, + values::Value, }; use std::{ collections::{HashMap, VecDeque}, fmt::Write, + sync::Arc, }; -pub type NativeFunction = - fn(&mut NativeContext, Vec, VecDeque) -> PartialVMResult; +pub type UnboxedNativeFunction = dyn Fn(&mut NativeContext, Vec, VecDeque) -> PartialVMResult + + Send + + Sync + + 'static; + +pub type NativeFunction = Arc; pub type NativeFunctionTable = Vec<(AccountAddress, Identifier, Identifier, NativeFunction)>; @@ -88,7 +92,6 @@ impl NativeFunctions { pub struct NativeContext<'a, 'b> { interpreter: &'a mut Interpreter, data_store: &'a mut dyn DataStore, - gas_status: &'a GasStatus<'a>, resolver: &'a Resolver<'a>, extensions: &'a mut NativeContextExtensions<'b>, } @@ -97,14 +100,12 @@ impl<'a, 'b> NativeContext<'a, 'b> { pub(crate) fn new( interpreter: &'a mut Interpreter, data_store: &'a mut dyn DataStore, - gas_status: &'a mut GasStatus, resolver: &'a Resolver<'a>, extensions: &'a mut NativeContextExtensions<'b>, ) -> Self { Self { interpreter, data_store, - gas_status, resolver, extensions, } @@ -117,10 +118,6 @@ impl<'a, 'b> NativeContext<'a, 'b> { .debug_print_stack_trace(buf, self.resolver.loader()) } - pub fn cost_table(&self) -> &CostTable { - self.gas_status.cost_table() - } - pub fn save_event( &mut self, guid: Vec, diff --git a/language/move-vm/runtime/src/runtime.rs b/language/move-vm/runtime/src/runtime.rs index d861ce27c2..9d299a8abb 100644 --- a/language/move-vm/runtime/src/runtime.rs +++ b/language/move-vm/runtime/src/runtime.rs @@ -28,7 +28,7 @@ use move_core_types::{ }; use move_vm_types::{ data_store::DataStore, - gas_schedule::GasStatus, + gas::GasMeter, loaded_data::runtime_types::Type, values::{Locals, Reference, VMValueCast, Value}, }; @@ -74,7 +74,7 @@ impl VMRuntime { modules: Vec>, sender: AccountAddress, data_store: &mut impl DataStore, - _gas_status: &mut GasStatus, + _gas_meter: &mut impl GasMeter, compat_check: bool, ) -> VMResult<()> { // deserialize the modules. Perform bounds check. After this indexes can be @@ -318,7 +318,7 @@ impl VMRuntime { return_types: Vec, serialized_args: Vec>, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, ) -> VMResult { let arg_types = param_types @@ -348,7 +348,7 @@ impl VMRuntime { ty_args, deserialized_args, data_store, - gas_status, + gas_meter, extensions, &self.loader, )?; @@ -383,7 +383,7 @@ impl VMRuntime { ty_args: Vec, serialized_args: Vec>, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, bypass_declared_entry_check: bool, ) -> VMResult { @@ -435,7 +435,7 @@ impl VMRuntime { return_, serialized_args, data_store, - gas_status, + gas_meter, extensions, ) } @@ -447,7 +447,7 @@ impl VMRuntime { ty_args: Vec, serialized_args: Vec>, data_store: &mut impl DataStore, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, ) -> VMResult { // load the script, perform verification @@ -469,7 +469,7 @@ impl VMRuntime { return_, serialized_args, data_store, - gas_status, + gas_meter, extensions, ) } diff --git a/language/move-vm/runtime/src/session.rs b/language/move-vm/runtime/src/session.rs index f2aa3ea13d..a1915fdca8 100644 --- a/language/move-vm/runtime/src/session.rs +++ b/language/move-vm/runtime/src/session.rs @@ -20,7 +20,7 @@ use move_core_types::{ }; use move_vm_types::{ data_store::DataStore, - gas_schedule::GasStatus, + gas::GasMeter, loaded_data::runtime_types::{CachedStructIndex, StructType, Type}, }; use std::{borrow::Borrow, sync::Arc}; @@ -74,7 +74,7 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { function_name: &IdentStr, ty_args: Vec, args: Vec>, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult { let bypass_declared_entry_check = false; self.runtime.execute_function( @@ -83,7 +83,7 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { ty_args, args, &mut self.data_cache, - gas_status, + gas_meter, &mut self.native_extensions, bypass_declared_entry_check, ) @@ -96,7 +96,7 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { function_name: &IdentStr, ty_args: Vec, args: Vec>, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult { let bypass_declared_entry_check = true; self.runtime.execute_function( @@ -105,7 +105,7 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { ty_args, args, &mut self.data_cache, - gas_status, + gas_meter, &mut self.native_extensions, bypass_declared_entry_check, ) @@ -132,14 +132,14 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { script: impl Borrow<[u8]>, ty_args: Vec, args: Vec>, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult { self.runtime.execute_script( script, ty_args, args, &mut self.data_cache, - gas_status, + gas_meter, &mut self.native_extensions, ) } @@ -161,9 +161,9 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { &mut self, module: Vec, sender: AccountAddress, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult<()> { - self.publish_module_bundle(vec![module], sender, gas_status) + self.publish_module_bundle(vec![module], sender, gas_meter) } /// Publish a series of modules. @@ -185,10 +185,10 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { &mut self, modules: Vec>, sender: AccountAddress, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult<()> { self.runtime - .publish_module_bundle(modules, sender, &mut self.data_cache, gas_status, true) + .publish_module_bundle(modules, sender, &mut self.data_cache, gas_meter, true) } /// Same like `publish_module_bundle` but relaxes compatibility checks. @@ -196,10 +196,10 @@ impl<'r, 'l, S: MoveResolver> Session<'r, 'l, S> { &mut self, modules: Vec>, sender: AccountAddress, - gas_status: &mut GasStatus, + gas_meter: &mut impl GasMeter, ) -> VMResult<()> { self.runtime - .publish_module_bundle(modules, sender, &mut self.data_cache, gas_status, false) + .publish_module_bundle(modules, sender, &mut self.data_cache, gas_meter, false) } pub fn num_mutated_accounts(&self, sender: &AccountAddress) -> u64 { diff --git a/language/move-vm/runtime/src/unit_tests/vm_arguments_tests.rs b/language/move-vm/runtime/src/unit_tests/vm_arguments_tests.rs index 60f2064fdc..45823b0b3b 100644 --- a/language/move-vm/runtime/src/unit_tests/vm_arguments_tests.rs +++ b/language/move-vm/runtime/src/unit_tests/vm_arguments_tests.rs @@ -23,7 +23,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::{StatusCode, StatusType}, }; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; // make a script with a given signature for main. fn make_script(parameters: Signature) -> Vec { @@ -286,13 +286,12 @@ fn call_script_with_args_ty_args_signers( let move_vm = MoveVM::new(vec![]).unwrap(); let remote_view = RemoteStore::new(); let mut session = move_vm.new_session(&remote_view); - let mut gas_status = GasStatus::new_unmetered(); session .execute_script( script, ty_args, combine_signers_and_args(signers, non_signer_args), - &mut gas_status, + &mut UnmeteredGasMeter, ) .map(|_| ()) } @@ -313,13 +312,12 @@ fn call_script_function_with_args_ty_args_signers( let id = module.self_id(); remote_view.add_module(module); let mut session = move_vm.new_session(&remote_view); - let mut gas_status = GasStatus::new_unmetered(); session.execute_function_bypass_visibility( &id, function_name.as_ident_str(), ty_args, combine_signers_and_args(signers, non_signer_args), - &mut gas_status, + &mut UnmeteredGasMeter, )?; Ok(()) } @@ -786,7 +784,6 @@ fn call_missing_item() { let function_name = IdentStr::new("foo").unwrap(); // mising module let move_vm = MoveVM::new(vec![]).unwrap(); - let mut gas_status = GasStatus::new_unmetered(); let mut remote_view = RemoteStore::new(); let mut session = move_vm.new_session(&remote_view); let error = session @@ -795,7 +792,7 @@ fn call_missing_item() { function_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .err() .unwrap(); @@ -812,7 +809,7 @@ fn call_missing_item() { function_name, vec![], Vec::>::new(), - &mut gas_status, + &mut UnmeteredGasMeter, ) .err() .unwrap(); diff --git a/language/move-vm/test-utils/Cargo.toml b/language/move-vm/test-utils/Cargo.toml index 4d391dadc6..809c23345c 100644 --- a/language/move-vm/test-utils/Cargo.toml +++ b/language/move-vm/test-utils/Cargo.toml @@ -13,8 +13,12 @@ edition = "2018" [dependencies] anyhow = "1.0.52" +once_cell = "1.7.2" +serde = { version = "1.0.124", features = ["derive", "rc"] } +move-binary-format = { path = "../../move-binary-format" } move-core-types = {path = "../../move-core/types" } +move-vm-types = { path = "../types" } move-table-extension = { path = "../../extensions/move-table-extension", optional = true } [features] diff --git a/language/move-vm/types/src/gas_schedule.rs b/language/move-vm/test-utils/src/gas_schedule.rs similarity index 73% rename from language/move-vm/types/src/gas_schedule.rs rename to language/move-vm/test-utils/src/gas_schedule.rs index 030304e6cd..2c7709c7d9 100644 --- a/language/move-vm/types/src/gas_schedule.rs +++ b/language/move-vm/test-utils/src/gas_schedule.rs @@ -12,22 +12,128 @@ use move_binary_format::{ file_format::{ Bytecode, ConstantPoolIndex, FieldHandleIndex, FieldInstantiationIndex, FunctionHandleIndex, FunctionInstantiationIndex, SignatureIndex, - StructDefInstantiationIndex, StructDefinitionIndex, NUMBER_OF_NATIVE_FUNCTIONS, + StructDefInstantiationIndex, StructDefinitionIndex, }, file_format_common::{instruction_key, Opcodes}, }; use move_core_types::{ gas_schedule::{ - AbstractMemorySize, CostTable, GasAlgebra, GasCarrier, GasConstants, GasCost, GasUnits, - InternalGasUnits, + AbstractMemorySize, GasAlgebra, GasCarrier, GasPrice, GasUnits, InternalGasUnits, }, vm_status::StatusCode, }; +use move_vm_types::gas::GasMeter; use once_cell::sync::Lazy; -use std::cmp::max; +use serde::{Deserialize, Serialize}; -static ZERO_COST_SCHEDULE: Lazy = - Lazy::new(|| zero_cost_schedule(NUMBER_OF_NATIVE_FUNCTIONS)); +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +pub struct GasConstants { + /// The cost per-byte read from global storage. + pub global_memory_per_byte_cost: InternalGasUnits, + + /// The cost per-byte written to storage. + pub global_memory_per_byte_write_cost: InternalGasUnits, + + /// The flat minimum amount of gas required for any transaction. + /// Charged at the start of execution. + pub min_transaction_gas_units: InternalGasUnits, + + /// Any transaction over this size will be charged an additional amount per byte. + pub large_transaction_cutoff: AbstractMemorySize, + + /// The units of gas that to be charged per byte over the `large_transaction_cutoff` in addition to + /// `min_transaction_gas_units` for transactions whose size exceeds `large_transaction_cutoff`. + pub intrinsic_gas_per_byte: InternalGasUnits, + + /// ~5 microseconds should equal one unit of computational gas. We bound the maximum + /// computational time of any given transaction at roughly 20 seconds. We want this number and + /// `MAX_PRICE_PER_GAS_UNIT` to always satisfy the inequality that + /// MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits::MAX) + /// NB: The bound is set quite high since custom scripts aren't allowed except from predefined + /// and vetted senders. + pub maximum_number_of_gas_units: GasUnits, + + /// The minimum gas price that a transaction can be submitted with. + pub min_price_per_gas_unit: GasPrice, + + /// The maximum gas unit price that a transaction can be submitted with. + pub max_price_per_gas_unit: GasPrice, + + pub max_transaction_size_in_bytes: GasCarrier, + + pub gas_unit_scaling_factor: GasCarrier, + pub default_account_size: AbstractMemorySize, +} + +impl GasConstants { + pub fn to_internal_units(&self, units: GasUnits) -> InternalGasUnits { + InternalGasUnits::new(units.get() * self.gas_unit_scaling_factor) + } + + pub fn to_external_units(&self, units: InternalGasUnits) -> GasUnits { + GasUnits::new(units.get() / self.gas_unit_scaling_factor) + } +} + +impl Default for GasConstants { + fn default() -> Self { + Self { + global_memory_per_byte_cost: InternalGasUnits::new(4), + global_memory_per_byte_write_cost: InternalGasUnits::new(9), + min_transaction_gas_units: InternalGasUnits::new(600), + large_transaction_cutoff: AbstractMemorySize::new(600), + intrinsic_gas_per_byte: InternalGasUnits::new(8), + maximum_number_of_gas_units: GasUnits::new(4_000_000), + min_price_per_gas_unit: GasPrice::new(0), + max_price_per_gas_unit: GasPrice::new(10_000), + max_transaction_size_in_bytes: 4096, + gas_unit_scaling_factor: 1000, + default_account_size: AbstractMemorySize::new(800), + } + } +} +/// The cost tables, keyed by the serialized form of the bytecode instruction. We use the +/// serialized form as opposed to the instruction enum itself as the key since this will be the +/// on-chain representation of bytecode instructions in the future. +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +pub struct CostTable { + pub instruction_table: Vec, + pub gas_constants: GasConstants, +} + +impl CostTable { + #[inline] + pub fn instruction_cost(&self, instr_index: u8) -> &GasCost { + debug_assert!(instr_index > 0 && instr_index <= (self.instruction_table.len() as u8)); + &self.instruction_table[(instr_index - 1) as usize] + } +} + +/// The `GasCost` tracks: +/// - instruction cost: how much time/computational power is needed to perform the instruction +/// - memory cost: how much memory is required for the instruction, and storage overhead +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct GasCost { + pub instruction_gas: InternalGasUnits, + pub memory_gas: InternalGasUnits, +} + +impl GasCost { + pub fn new(instr_gas: GasCarrier, mem_gas: GasCarrier) -> Self { + Self { + instruction_gas: InternalGasUnits::new(instr_gas), + memory_gas: InternalGasUnits::new(mem_gas), + } + } + + /// Convert a GasCost to a total gas charge in `InternalGasUnits`. + #[inline] + pub fn total(&self) -> InternalGasUnits { + self.instruction_gas.add(self.memory_gas) + } +} + +static ZERO_COST_SCHEDULE: Lazy = Lazy::new(zero_cost_schedule); /// The Move VM implementation of state for gas metering. /// @@ -96,8 +202,25 @@ impl<'a> GasStatus<'a> { } } + /// Charge gas related to the overall size of a transaction and fail if not enough + /// gas units are left. + pub fn charge_intrinsic_gas( + &mut self, + intrinsic_cost: AbstractMemorySize, + ) -> VMResult<()> { + let cost = calculate_intrinsic_gas(intrinsic_cost, &self.cost_table.gas_constants); + self.deduct_gas(cost) + .map_err(|e| e.finish(Location::Undefined)) + } + + pub fn set_metering(&mut self, enabled: bool) { + self.charge = enabled + } +} + +impl<'a> GasMeter for GasStatus<'a> { /// Charge an instruction over data with a given size and fail if not enough gas units are left. - pub fn charge_instr_with_size( + fn charge_instr_with_size( &mut self, opcode: Opcodes, size: AbstractMemorySize, @@ -114,30 +237,16 @@ impl<'a> GasStatus<'a> { } /// Charge an instruction and fail if not enough gas units are left. - pub fn charge_instr(&mut self, opcode: Opcodes) -> PartialVMResult<()> { + fn charge_instr(&mut self, opcode: Opcodes) -> PartialVMResult<()> { self.deduct_gas(self.cost_table.instruction_cost(opcode as u8).total()) } - /// Charge gas related to the overall size of a transaction and fail if not enough - /// gas units are left. - pub fn charge_intrinsic_gas( - &mut self, - intrinsic_cost: AbstractMemorySize, - ) -> VMResult<()> { - let cost = calculate_intrinsic_gas(intrinsic_cost, &self.cost_table.gas_constants); - self.deduct_gas(cost) - .map_err(|e| e.finish(Location::Undefined)) - } - - pub fn set_metering(&mut self, enabled: bool) { - self.charge = enabled + fn charge_in_native_unit(&mut self, amount: u64) -> PartialVMResult<()> { + self.deduct_gas(InternalGasUnits::new(amount)) } } -pub fn new_from_instructions( - mut instrs: Vec<(Bytecode, GasCost)>, - native_table: Vec, -) -> CostTable { +pub fn new_from_instructions(mut instrs: Vec<(Bytecode, GasCost)>) -> CostTable { instrs.sort_by_key(|cost| instruction_key(&cost.0)); if cfg!(debug_assertions) { @@ -159,7 +268,6 @@ pub fn new_from_instructions( .collect::>(); CostTable { instruction_table, - native_table, gas_constants: GasConstants::default(), } } @@ -280,19 +388,13 @@ pub fn zero_cost_instruction_table() -> Vec<(Bytecode, GasCost)> { // Only used for genesis and for tests where we need a cost table and // don't have a genesis storage state. -pub fn zero_cost_schedule(num_of_native_funcs: usize) -> CostTable { +pub fn zero_cost_schedule() -> CostTable { // The actual costs for the instructions in this table _DO NOT MATTER_. This is only used // for genesis and testing, and for these cases we don't need to worry // about the actual gas for instructions. The only thing we care about is having an entry // in the gas schedule for each instruction. let instrs = zero_cost_instruction_table(); - // length of native_table vector should be at least 18 due to the fact that there's a - // builtin native function cost EMIT_EVENT which indexed 17 in the vector - let num_of_native_funcs = max(num_of_native_funcs, 18); - let native_table = (0..num_of_native_funcs) - .map(|_| GasCost::new(0, 0)) - .collect::>(); - new_from_instructions(instrs, native_table) + new_from_instructions(instrs) } pub fn bytecode_instruction_costs() -> Vec<(Bytecode, GasCost)> { @@ -416,34 +518,7 @@ pub static INITIAL_COST_SCHEDULE: Lazy = Lazy::new(|| { // Note that the DiemVM is expecting the table sorted by instruction order. instrs.sort_by_key(|cost| instruction_key(&cost.0)); - use NativeCostIndex as N; - - let mut native_table = vec![ - (N::SHA2_256, GasCost::new(21, 1)), - (N::SHA3_256, GasCost::new(64, 1)), - (N::ED25519_VERIFY, GasCost::new(61, 1)), - (N::ED25519_THRESHOLD_VERIFY, GasCost::new(3351, 1)), - (N::BCS_TO_BYTES, GasCost::new(181, 1)), - (N::LENGTH, GasCost::new(98, 1)), - (N::EMPTY, GasCost::new(84, 1)), - (N::BORROW, GasCost::new(1334, 1)), - (N::BORROW_MUT, GasCost::new(1902, 1)), - (N::PUSH_BACK, GasCost::new(53, 1)), - (N::POP_BACK, GasCost::new(227, 1)), - (N::DESTROY_EMPTY, GasCost::new(572, 1)), - (N::SWAP, GasCost::new(1436, 1)), - (N::ED25519_VALIDATE_KEY, GasCost::new(26, 1)), - (N::SIGNER_BORROW, GasCost::new(353, 1)), - (N::CREATE_SIGNER, GasCost::new(24, 1)), - (N::DESTROY_SIGNER, GasCost::new(212, 1)), - (N::EMIT_EVENT, GasCost::new(52, 1)), - ]; - native_table.sort_by_key(|cost| cost.0 as u64); - let raw_native_table = native_table - .into_iter() - .map(|(_, cost)| cost) - .collect::>(); - new_from_instructions(instrs, raw_native_table) + new_from_instructions(instrs) }); /// Calculate the intrinsic gas for the transaction based upon its size in bytes/words. @@ -460,35 +535,3 @@ pub fn calculate_intrinsic_gas( min_transaction_fee.unitary_cast() } } - -// TODO: need to refactor native gas calculation so it is extensible. Currently we -// have hardcoded here the stdlib natives. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -#[repr(u8)] -pub enum NativeCostIndex { - SHA2_256 = 0, - SHA3_256 = 1, - ED25519_VERIFY = 2, - ED25519_THRESHOLD_VERIFY = 3, - BCS_TO_BYTES = 4, - LENGTH = 5, - EMPTY = 6, - BORROW = 7, - BORROW_MUT = 8, - PUSH_BACK = 9, - POP_BACK = 10, - DESTROY_EMPTY = 11, - SWAP = 12, - ED25519_VALIDATE_KEY = 13, - SIGNER_BORROW = 14, - CREATE_SIGNER = 15, - DESTROY_SIGNER = 16, - EMIT_EVENT = 17, -} - -impl From for u8 { - fn from(index: NativeCostIndex) -> Self { - index as u8 - } -} diff --git a/language/move-vm/test-utils/src/lib.rs b/language/move-vm/test-utils/src/lib.rs index 6b65217408..a56aba81a8 100644 --- a/language/move-vm/test-utils/src/lib.rs +++ b/language/move-vm/test-utils/src/lib.rs @@ -6,4 +6,5 @@ mod storage; +pub mod gas_schedule; pub use storage::{BlankStorage, DeltaStorage, InMemoryStorage}; diff --git a/language/move-vm/test-utils/src/storage.rs b/language/move-vm/test-utils/src/storage.rs index f30da18a95..0c3ac6147e 100644 --- a/language/move-vm/test-utils/src/storage.rs +++ b/language/move-vm/test-utils/src/storage.rs @@ -58,13 +58,8 @@ impl TableResolver for BlankStorage { Ok(None) } - fn operation_cost( - &self, - _op: TableOperation, - _key_size: usize, - _val_size: usize, - ) -> InternalGasUnits { - InternalGasUnits::new(1) + fn operation_cost(&self, _op: TableOperation, _key_size: usize, _val_size: usize) -> u64 { + 1 } } @@ -119,12 +114,7 @@ impl<'a, 'b, S: TableResolver> TableResolver for DeltaStorage<'a, 'b, S> { self.base.resolve_table_entry(handle, key) } - fn operation_cost( - &self, - op: TableOperation, - key_size: usize, - val_size: usize, - ) -> InternalGasUnits { + fn operation_cost(&self, op: TableOperation, key_size: usize, val_size: usize) -> u64 { // TODO: No support for table deltas self.base.operation_cost(op, key_size, val_size) } @@ -340,12 +330,7 @@ impl TableResolver for InMemoryStorage { Ok(self.tables.get(handle).and_then(|t| t.get(key).cloned())) } - fn operation_cost( - &self, - _op: TableOperation, - _key_size: usize, - _val_size: usize, - ) -> InternalGasUnits { - InternalGasUnits::new(1) + fn operation_cost(&self, _op: TableOperation, _key_size: usize, _val_size: usize) -> u64 { + 1 } } diff --git a/language/move-vm/types/src/gas.rs b/language/move-vm/types/src/gas.rs new file mode 100644 index 0000000000..cc85808169 --- /dev/null +++ b/language/move-vm/types/src/gas.rs @@ -0,0 +1,47 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use move_binary_format::{errors::PartialVMResult, file_format_common::Opcodes}; +use move_core_types::gas_schedule::{AbstractMemorySize, GasCarrier}; + +pub trait GasMeter { + /// Charge an instruction and fail if not enough gas units are left. + fn charge_instr(&mut self, opcode: Opcodes) -> PartialVMResult<()>; + + /// Charge an instruction over data with a given size and fail if not enough gas units are left. + fn charge_instr_with_size( + &mut self, + opcode: Opcodes, + size: AbstractMemorySize, + ) -> PartialVMResult<()>; + + /// Charge a given amount in the unit of measurement native to the GasMeter implementation. + /// Should fail if not enough gas units are left. + /// + /// This is used for metering native functions currently. + /// However, in the future, we may want to remove this and directly pass a reference to the GasMeter + /// instance to the native functions to allow gas to be deducted during computation. + fn charge_in_native_unit(&mut self, amount: u64) -> PartialVMResult<()>; +} + +/// A dummy gas meter that does not meter anything. +/// Charge operations will always succeed. +pub struct UnmeteredGasMeter; + +impl GasMeter for UnmeteredGasMeter { + fn charge_instr(&mut self, _opcode: Opcodes) -> PartialVMResult<()> { + Ok(()) + } + + fn charge_instr_with_size( + &mut self, + _opcode: Opcodes, + _size: AbstractMemorySize, + ) -> PartialVMResult<()> { + Ok(()) + } + + fn charge_in_native_unit(&mut self, _amount: u64) -> PartialVMResult<()> { + Ok(()) + } +} diff --git a/language/move-vm/types/src/lib.rs b/language/move-vm/types/src/lib.rs index e857e9335d..691ef1d763 100644 --- a/language/move-vm/types/src/lib.rs +++ b/language/move-vm/types/src/lib.rs @@ -23,7 +23,7 @@ macro_rules! debug_writeln { } pub mod data_store; -pub mod gas_schedule; +pub mod gas; pub mod loaded_data; pub mod natives; pub mod values; diff --git a/language/move-vm/types/src/loaded_data/runtime_types.rs b/language/move-vm/types/src/loaded_data/runtime_types.rs index fcbb050ebe..e986e5f891 100644 --- a/language/move-vm/types/src/loaded_data/runtime_types.rs +++ b/language/move-vm/types/src/loaded_data/runtime_types.rs @@ -2,11 +2,18 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use std::ops::Add; + use move_binary_format::{ errors::{PartialVMError, PartialVMResult}, file_format::{AbilitySet, StructDefinitionIndex, StructTypeParameter}, }; -use move_core_types::{identifier::Identifier, language_storage::ModuleId, vm_status::StatusCode}; +use move_core_types::{ + gas_schedule::{AbstractMemorySize, GasAlgebra, GasCarrier}, + identifier::Identifier, + language_storage::ModuleId, + vm_status::StatusCode, +}; pub const TYPE_DEPTH_MAX: usize = 256; @@ -98,4 +105,24 @@ impl Type { 1, ) } + + const BASE_MEMORY_SIZE: GasCarrier = 1; + + pub fn size(&self) -> AbstractMemorySize { + use Type::*; + + match self { + TyParam(_) | Bool | U8 | U64 | U128 | Address | Signer => { + AbstractMemorySize::new(Type::BASE_MEMORY_SIZE) + } + Vector(ty) | Reference(ty) | MutableReference(ty) => { + AbstractMemorySize::new(Type::BASE_MEMORY_SIZE).map2(ty.size(), Add::add) + } + Struct(_) => AbstractMemorySize::new(Type::BASE_MEMORY_SIZE), + StructInstantiation(_, tys) => tys.iter().fold( + AbstractMemorySize::new(Type::BASE_MEMORY_SIZE), + |acc, ty| acc.map2(ty.size(), Add::add), + ), + } + } } diff --git a/language/move-vm/types/src/natives/function.rs b/language/move-vm/types/src/natives/function.rs index f7ea55c88e..ed46787747 100644 --- a/language/move-vm/types/src/natives/function.rs +++ b/language/move-vm/types/src/natives/function.rs @@ -18,9 +18,6 @@ //! function. use crate::values::Value; -use move_core_types::gas_schedule::{ - AbstractMemorySize, CostTable, GasAlgebra, GasCarrier, InternalGasUnits, -}; use smallvec::{smallvec, SmallVec}; pub use move_binary_format::errors::{PartialVMError, PartialVMResult}; @@ -36,15 +33,14 @@ pub use move_core_types::vm_status::StatusCode; /// Errors (typically user errors and aborts) that are logically part of the function execution /// must be expressed in a `NativeResult` with a cost and a VMStatus. pub struct NativeResult { - /// The cost for running that function, whether successfully or not. - pub cost: InternalGasUnits, /// Result of execution. This is either the return values or the error to report. + pub cost: u64, pub result: Result, u64>, } impl NativeResult { /// Return values of a successful execution. - pub fn ok(cost: InternalGasUnits, values: SmallVec<[Value; 1]>) -> Self { + pub fn ok(cost: u64, values: SmallVec<[Value; 1]>) -> Self { NativeResult { cost, result: Ok(values), @@ -55,7 +51,7 @@ impl NativeResult { /// failure of the VM which would raise a `PartialVMError` error directly. /// The only thing the funciton can specify is its abort code, as if it had invoked the `Abort` /// bytecode instruction - pub fn err(cost: InternalGasUnits, abort_code: u64) -> Self { + pub fn err(cost: u64, abort_code: u64) -> Self { NativeResult { cost, result: Err(abort_code), @@ -64,7 +60,7 @@ impl NativeResult { /// Convert a PartialVMResult<()> into a PartialVMResult pub fn map_partial_vm_result_empty( - cost: InternalGasUnits, + cost: u64, res: PartialVMResult<()>, ) -> PartialVMResult { let result = match res { @@ -85,7 +81,7 @@ impl NativeResult { /// Convert a PartialVMResult into a PartialVMResult pub fn map_partial_vm_result_one( - cost: InternalGasUnits, + cost: u64, res: PartialVMResult, ) -> PartialVMResult { let result = match res { @@ -105,19 +101,6 @@ impl NativeResult { } } -/// Return the native gas entry in `CostTable` for the given key. -/// The key is the specific native function index known to `CostTable`. -pub fn native_gas( - table: &CostTable, - native_table_idx: impl Into, - size: usize, -) -> InternalGasUnits { - let gas_amt = table.native_cost(native_table_idx.into()); - let memory_size = AbstractMemorySize::new(std::cmp::max(1, size) as GasCarrier); - debug_assert!(memory_size.get() > 0); - gas_amt.total().mul(memory_size) -} - /// Return the argument at the top of the stack. /// /// Arguments are passed to a native as a stack with first arg at the bottom of the stack. diff --git a/language/testing-infra/test-generation/src/lib.rs b/language/testing-infra/test-generation/src/lib.rs index 49958e432c..3cb74064fb 100644 --- a/language/testing-infra/test-generation/src/lib.rs +++ b/language/testing-infra/test-generation/src/lib.rs @@ -36,7 +36,7 @@ use move_core_types::{ }; use move_vm_runtime::move_vm::MoveVM; use move_vm_test_utils::{DeltaStorage, InMemoryStorage}; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_types::gas::UnmeteredGasMeter; use once_cell::sync::Lazy; use rand::{rngs::StdRng, Rng, SeedableRng}; use std::{fs, io::Write, panic, thread}; @@ -126,6 +126,7 @@ fn execute_function_in_module( { let vm = MoveVM::new(move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), )) .unwrap(); @@ -136,13 +137,12 @@ fn execute_function_in_module( let delta_storage = DeltaStorage::new(storage, &changeset); let mut sess = vm.new_session(&delta_storage); - let mut gas_status = GasStatus::new_unmetered(); sess.execute_function_bypass_visibility( &module_id, entry_name, ty_args, args, - &mut gas_status, + &mut UnmeteredGasMeter, )?; Ok(()) diff --git a/language/testing-infra/transactional-test-runner/src/vm_test_harness.rs b/language/testing-infra/transactional-test-runner/src/vm_test_harness.rs index 1e1fcfd7cd..47e1238a7b 100644 --- a/language/testing-infra/transactional-test-runner/src/vm_test_harness.rs +++ b/language/testing-infra/transactional-test-runner/src/vm_test_harness.rs @@ -34,8 +34,7 @@ use move_vm_runtime::{ move_vm::MoveVM, session::{SerializedReturnValues, Session}, }; -use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::GasStatus; +use move_vm_test_utils::{gas_schedule::GasStatus, InMemoryStorage}; use once_cell::sync::Lazy; const STD_ADDR: AccountAddress = AccountAddress::ONE; @@ -292,10 +291,15 @@ impl<'a> SimpleVMTestAdapter<'a> { f: impl FnOnce(&mut Session, &mut GasStatus) -> VMResult, ) -> VMResult { // start session - let vm = MoveVM::new(move_stdlib::natives::all_natives(STD_ADDR)).unwrap(); + let vm = MoveVM::new(move_stdlib::natives::all_natives( + STD_ADDR, + // TODO: come up with a suitable gas schedule + move_stdlib::natives::GasParameters::zeros(), + )) + .unwrap(); let (mut session, mut gas_status) = { let gas_status = move_cli::sandbox::utils::get_gas_status( - &move_vm_types::gas_schedule::INITIAL_COST_SCHEDULE, + &move_vm_test_utils::gas_schedule::INITIAL_COST_SCHEDULE, gas_budget, ) .unwrap(); diff --git a/language/tools/move-cli/Cargo.toml b/language/tools/move-cli/Cargo.toml index feb3bad0df..c948568968 100644 --- a/language/tools/move-cli/Cargo.toml +++ b/language/tools/move-cli/Cargo.toml @@ -35,6 +35,7 @@ move-table-extension = { path = "../../extensions/move-table-extension", optiona move-symbol-pool = { path = "../../move-symbol-pool" } move-vm-types = { path = "../../move-vm/types" } move-vm-runtime = { path = "../../move-vm/runtime", features = ["debugging"] } +move-vm-test-utils = { path = "../../move-vm/test-utils" } read-write-set = { path = "../read-write-set" } read-write-set-dynamic = { path = "../read-write-set/dynamic" } move-resource-viewer = { path = "../move-resource-viewer" } diff --git a/language/tools/move-cli/src/lib.rs b/language/tools/move-cli/src/lib.rs index 2fa155bac3..8c305af1ad 100644 --- a/language/tools/move-cli/src/lib.rs +++ b/language/tools/move-cli/src/lib.rs @@ -24,10 +24,10 @@ const BCS_EXTENSION: &str = "bcs"; use anyhow::Result; use clap::Parser; use move_core_types::{ - account_address::AccountAddress, errmap::ErrorMapping, gas_schedule::CostTable, - identifier::Identifier, + account_address::AccountAddress, errmap::ErrorMapping, identifier::Identifier, }; use move_vm_runtime::native_functions::NativeFunction; +use move_vm_test_utils::gas_schedule::CostTable; use std::path::PathBuf; type NativeFunctionRecord = (AccountAddress, Identifier, Identifier, NativeFunction); @@ -99,6 +99,9 @@ pub fn run_cli( move_args: Move, cmd: Command, ) -> Result<()> { + // TODO: right now, the gas metering story for move-cli (as a library) is a bit of a mess. + // 1. It's still using the old CostTable. + // 2. The CostTable only affects sandbox runs, but not unit tests, which use a unit cost table. match cmd { Command::Build(c) => c.execute(move_args.package_path, move_args.build_config), Command::Coverage(c) => c.execute(move_args.package_path, move_args.build_config), diff --git a/language/tools/move-cli/src/main.rs b/language/tools/move-cli/src/main.rs index 1bef3d6190..f2f29cc402 100644 --- a/language/tools/move-cli/src/main.rs +++ b/language/tools/move-cli/src/main.rs @@ -4,13 +4,16 @@ use anyhow::Result; use move_core_types::{account_address::AccountAddress, errmap::ErrorMapping}; +use move_stdlib::natives::{all_natives, nursery_natives, GasParameters, NurseryGasParameters}; fn main() -> Result<()> { let error_descriptions: ErrorMapping = bcs::from_bytes(move_stdlib::error_descriptions())?; - let cost_table = &move_vm_types::gas_schedule::INITIAL_COST_SCHEDULE; - move_cli::move_cli( - move_stdlib::natives::all_natives(AccountAddress::from_hex_literal("0x1").unwrap()), - cost_table, - &error_descriptions, - ) + let cost_table = &move_vm_test_utils::gas_schedule::INITIAL_COST_SCHEDULE; + let addr = AccountAddress::from_hex_literal("0x1").unwrap(); + let natives = all_natives(addr, GasParameters::zeros()) + .into_iter() + .chain(nursery_natives(addr, NurseryGasParameters::zeros())) + .collect(); + + move_cli::move_cli(natives, cost_table, &error_descriptions) } diff --git a/language/tools/move-cli/src/sandbox/cli.rs b/language/tools/move-cli/src/sandbox/cli.rs index a338613a58..3c897739b5 100644 --- a/language/tools/move-cli/src/sandbox/cli.rs +++ b/language/tools/move-cli/src/sandbox/cli.rs @@ -12,10 +12,11 @@ use crate::{ use anyhow::Result; use clap::Parser; use move_core_types::{ - errmap::ErrorMapping, gas_schedule::CostTable, language_storage::TypeTag, parser, + errmap::ErrorMapping, language_storage::TypeTag, parser, transaction_argument::TransactionArgument, }; use move_package::compilation::package_layout::CompiledPackageLayout; +use move_vm_test_utils::gas_schedule::CostTable; use std::{ fs, path::{Path, PathBuf}, diff --git a/language/tools/move-cli/src/sandbox/commands/publish.rs b/language/tools/move-cli/src/sandbox/commands/publish.rs index a1b226ff9e..d7a193e5c7 100644 --- a/language/tools/move-cli/src/sandbox/commands/publish.rs +++ b/language/tools/move-cli/src/sandbox/commands/publish.rs @@ -11,9 +11,9 @@ use crate::{ }; use anyhow::{bail, Result}; use move_command_line_common::env::get_bytecode_version_from_env; -use move_core_types::gas_schedule::CostTable; use move_package::compilation::compiled_package::CompiledPackage; use move_vm_runtime::move_vm::MoveVM; +use move_vm_test_utils::gas_schedule::CostTable; use std::collections::BTreeMap; pub fn publish( diff --git a/language/tools/move-cli/src/sandbox/commands/run.rs b/language/tools/move-cli/src/sandbox/commands/run.rs index 8b4077c2c8..17d0d07937 100644 --- a/language/tools/move-cli/src/sandbox/commands/run.rs +++ b/language/tools/move-cli/src/sandbox/commands/run.rs @@ -15,7 +15,6 @@ use move_command_line_common::env::get_bytecode_version_from_env; use move_core_types::{ account_address::AccountAddress, errmap::ErrorMapping, - gas_schedule::CostTable, identifier::IdentStr, language_storage::TypeTag, transaction_argument::{convert_txn_args, TransactionArgument}, @@ -23,6 +22,7 @@ use move_core_types::{ }; use move_package::compilation::compiled_package::CompiledPackage; use move_vm_runtime::move_vm::MoveVM; +use move_vm_test_utils::gas_schedule::CostTable; use std::{fs, path::Path}; pub fn run( diff --git a/language/tools/move-cli/src/sandbox/utils/mod.rs b/language/tools/move-cli/src/sandbox/utils/mod.rs index 38b582bc01..ee4ad36b15 100644 --- a/language/tools/move-cli/src/sandbox/utils/mod.rs +++ b/language/tools/move-cli/src/sandbox/utils/mod.rs @@ -31,7 +31,6 @@ use move_core_types::{ use move_ir_types::location::Loc; use move_package::compilation::compiled_package::CompiledUnitWithSource; use move_resource_viewer::{AnnotatedMoveStruct, MoveValueAnnotator}; -use move_vm_types::gas_schedule::GasStatus; use std::{ collections::{BTreeMap, HashMap}, fs, @@ -42,7 +41,7 @@ pub mod on_disk_state_view; pub mod package_context; use move_bytecode_utils::module_cache::GetModule; -use move_core_types::gas_schedule::CostTable; +use move_vm_test_utils::gas_schedule::{CostTable, GasStatus}; pub use on_disk_state_view::*; pub use package_context::*; diff --git a/language/tools/move-unit-test/src/test_runner.rs b/language/tools/move-unit-test/src/test_runner.rs index dd2e6635f4..0c442951f0 100644 --- a/language/tools/move-unit-test/src/test_runner.rs +++ b/language/tools/move-unit-test/src/test_runner.rs @@ -18,7 +18,7 @@ use move_compiler::{ use move_core_types::{ account_address::AccountAddress, effects::ChangeSet, - gas_schedule::{CostTable, GasAlgebra, GasCost, GasUnits}, + gas_schedule::{GasAlgebra, GasUnits}, identifier::IdentStr, value::serialize_values, vm_status::StatusCode, @@ -34,8 +34,10 @@ use move_stackless_bytecode_interpreter::{ StacklessBytecodeInterpreter, }; use move_vm_runtime::{move_vm::MoveVM, native_functions::NativeFunctionTable}; -use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas_schedule::{zero_cost_schedule, GasStatus}; +use move_vm_test_utils::{ + gas_schedule::{zero_cost_schedule, CostTable, GasCost, GasStatus}, + InMemoryStorage, +}; use rayon::prelude::*; use std::{collections::BTreeMap, io::Write, marker::Send, sync::Mutex, time::Instant}; @@ -75,14 +77,11 @@ pub struct TestRunner { /// A gas schedule where every instruction has a cost of "1". This is used to bound execution of a /// test to a certain number of ticks. -fn unit_cost_table(num_of_native_funcs: usize) -> CostTable { - let mut cost_schedule = zero_cost_schedule(num_of_native_funcs); +fn unit_cost_table() -> CostTable { + let mut cost_schedule = zero_cost_schedule(); cost_schedule.instruction_table.iter_mut().for_each(|cost| { *cost = GasCost::new(1, 1); }); - cost_schedule.native_table.iter_mut().for_each(|cost| { - *cost = GasCost::new(1, 1); - }); cost_schedule } @@ -142,6 +141,8 @@ impl TestRunner { save_storage_state_on_failure: bool, report_stacktrace_on_abort: bool, tests: TestPlan, + // TODO: maybe we should require the clients to always pass in a list of native functions so + // we don't have to make assumptions about their gas parameters. native_function_table: Option, named_address_values: BTreeMap, #[cfg(feature = "evm-backend")] evm: bool, @@ -154,9 +155,11 @@ impl TestRunner { let modules = tests.module_info.values().map(|info| &info.module); let starting_storage_state = setup_test_storage(modules)?; let native_function_table = native_function_table.unwrap_or_else(|| { - move_stdlib::natives::all_natives(AccountAddress::from_hex_literal("0x1").unwrap()) + move_stdlib::natives::all_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), + ) }); - let num_of_native_funcs = native_function_table.len(); Ok(Self { testing_config: SharedTestingConfig { save_storage_state_on_failure, @@ -164,7 +167,12 @@ impl TestRunner { starting_storage_state, execution_bound, native_function_table, - cost_table: unit_cost_table(num_of_native_funcs), + // TODO: our current implementation uses a unit cost table to prevent programs from + // running indefinitely. This should probably be done in a different way, like halting + // after executing a certain number of instructions or setting a timer. + // + // From the API standpoint, we should let the client specify the cost table. + cost_table: unit_cost_table(), source_files, check_stackless_vm, verbose, From 7d4d265b04b53b2329956a13efe3a02c30186752 Mon Sep 17 00:00:00 2001 From: Leofis G Date: Tue, 26 Jul 2022 06:22:16 +0800 Subject: [PATCH 007/169] Fixed bug. (#303) --- .../examples/experimental/basic-coin/sources/BasicCoin.move | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/language/documentation/examples/experimental/basic-coin/sources/BasicCoin.move b/language/documentation/examples/experimental/basic-coin/sources/BasicCoin.move index a6aa8d2008..07afeca9a6 100644 --- a/language/documentation/examples/experimental/basic-coin/sources/BasicCoin.move +++ b/language/documentation/examples/experimental/basic-coin/sources/BasicCoin.move @@ -1,6 +1,6 @@ /// This module defines a minimal and generic Coin and Balance. module BasicCoin::BasicCoin { - use std::errors; + use std::error; use std::signer; /// Error codes @@ -20,7 +20,7 @@ module BasicCoin::BasicCoin { public fun publish_balance(account: &signer) { let empty_coin = Coin { value: 0 }; - assert!(!exists>(signer::address_of(account)), errors::already_published(EALREADY_HAS_BALANCE)); + assert!(!exists>(signer::address_of(account)), error::already_exists(EALREADY_HAS_BALANCE)); move_to(account, Balance { coin: empty_coin }); } From 514701b7cb7c4492601c9aae0aef4d6b6347dd26 Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Wed, 27 Jul 2022 00:20:28 -0400 Subject: [PATCH 008/169] [move-prover] treat store as copy in borrow analysis (#308) --- .../bytecode/src/borrow_analysis.rs | 4 +- .../bytecode/tests/borrow/basic_test.exp | 86 ++--- .../tests/borrow_strong/basic_test.exp | 308 ++++++++---------- .../tests/memory_instr/basic_test.exp | 37 ++- .../functional/loops_with_memory_ops.cvc5_exp | 113 +++++++ .../functional/loops_with_memory_ops.exp | 23 +- .../functional/loops_with_memory_ops.move | 2 +- .../functional/mut_ref_arg_return.move | 36 ++ 8 files changed, 355 insertions(+), 254 deletions(-) create mode 100644 language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp create mode 100644 language/move-prover/tests/sources/functional/mut_ref_arg_return.move diff --git a/language/move-prover/bytecode/src/borrow_analysis.rs b/language/move-prover/bytecode/src/borrow_analysis.rs index d5f1bc9b82..5902c0a5b5 100644 --- a/language/move-prover/bytecode/src/borrow_analysis.rs +++ b/language/move-prover/bytecode/src/borrow_analysis.rs @@ -546,11 +546,11 @@ impl<'a> TransferFunctions for BorrowAnalysis<'a> { let dest_node = self.borrow_node(*dest); let src_node = self.borrow_node(*src); match kind { - AssignKind::Move | AssignKind::Store => { + AssignKind::Move => { self.remap_borrow_node(state, &src_node, &dest_node); state.moved_nodes.insert(src_node); } - AssignKind::Copy => { + AssignKind::Copy | AssignKind::Store => { state.add_node(dest_node.clone()); state.add_edge(src_node, dest_node, BorrowEdge::Direct); } diff --git a/language/move-prover/bytecode/tests/borrow/basic_test.exp b/language/move-prover/bytecode/tests/borrow/basic_test.exp index 2372575562..b98d5eeef8 100644 --- a/language/move-prover/bytecode/tests/borrow/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow/basic_test.exp @@ -422,75 +422,61 @@ fun TestBorrow::test7($t0|b: bool) { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))} 5: $t3 := $t6 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 6: if ($t0) goto 14 else goto 17 - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 7: label L0 - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 8: destroy($t6) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 9: $t3 := borrow_local($t2) # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 10: label L2 # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 11: $t7 := 0 # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 12: TestBorrow::test3($t3, $t7) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 13: return () - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 14: label L3 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 15: destroy($t3) - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 16: goto 7 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 17: label L4 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 18: destroy($t6) # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t6) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} 19: goto 10 } diff --git a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp index 6af0e726d6..f6c8c85f2c 100644 --- a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp @@ -417,95 +417,83 @@ fun TestBorrow::test10($t0|b: bool): TestBorrow::R { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 5: $t2 := $t7 - # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 6: if ($t0) goto 18 else goto 21 - # live_nodes: LocalRoot($t0), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 7: label L0 - # live_nodes: LocalRoot($t0), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 8: destroy($t7) # live_nodes: LocalRoot($t0), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 9: $t2 := TestBorrow::test9($t0, $t6) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # moved_nodes: Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 10: goto 13 # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 11: label L2 # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 12: destroy($t6) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # moved_nodes: Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 13: label L3 # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # moved_nodes: Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 14: $t8 := 0 # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # moved_nodes: Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 15: write_ref($t2, $t8) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # moved_nodes: Reference($t6) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 16: $t9 := move($t1) # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t9) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6)), (.y (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t9))} + # moved_nodes: LocalRoot($t1), Reference($t6) + # borrowed_by: LocalRoot($t9) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t9))}, Reference($t7) -> {(.x (u64), Reference($t6))} 17: return $t9 - # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 18: label L4 - # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 19: destroy($t2) - # live_nodes: LocalRoot($t0), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 20: goto 7 - # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 21: label L5 - # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 22: destroy($t7) # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6) - # moved_nodes: Reference($t7) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 23: goto 11 } @@ -658,75 +646,61 @@ fun TestBorrow::test7($t0|b: bool) { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))} # borrows_from: Reference($t8) -> {(@, LocalRoot($t1))} 7: $t3 := $t8 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 8: if ($t0) goto 16 else goto 19 - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 9: label L0 - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 10: destroy($t8) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 11: $t3 := borrow_local($t2) # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 12: label L2 # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 13: $t9 := 0 # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 14: TestBorrow::test3($t3, $t9) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, LocalRoot($t2) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1)), (@, LocalRoot($t2))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 15: return () - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 16: label L3 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 17: destroy($t3) - # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 18: goto 9 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 19: label L4 - # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 20: destroy($t8) # live_nodes: LocalRoot($t0), Reference($t3) - # moved_nodes: Reference($t8) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} 21: goto 12 } @@ -913,95 +887,77 @@ fun TestBorrow::test9($t0|b: bool, $t1|r_ref: &mut TestBorrow::R): &mut u64 { # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))} # borrows_from: Reference($t3) -> {(.x (u64), Reference($t1))} 1: $t2 := $t3 - # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 2: if ($t0) goto 14 else goto 17 - # live_nodes: LocalRoot($t0), Reference($t1) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 3: label L0 - # live_nodes: LocalRoot($t0), Reference($t1) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 4: destroy($t3) # live_nodes: LocalRoot($t0), Reference($t1) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 5: $t2 := borrow_field.y($t1) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 6: goto 9 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 7: label L2 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 8: destroy($t1) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 9: label L3 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 10: $t4 := 0 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 11: write_ref($t2, $t4) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 12: trace_local[r_ref]($t1) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2)), (.y (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.y (u64), Reference($t2)), (.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t1)), (@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 13: return $t2 - # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 14: label L4 - # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 15: destroy($t2) - # live_nodes: LocalRoot($t0), Reference($t1) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 16: goto 3 - # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 17: label L5 - # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2), Reference($t3) + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 18: destroy($t3) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) - # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t2))} - # borrows_from: Reference($t2) -> {(.x (u64), Reference($t1))} + # borrowed_by: Reference($t1) -> {(.x (u64), Reference($t3))}, Reference($t3) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, Reference($t3))}, Reference($t3) -> {(.x (u64), Reference($t1))} 19: goto 7 } @@ -1014,5 +970,5 @@ borrowed_by: Reference($t0) -> {(.x (u64), Return(0))} borrows_from: Return(0) -> {(.x (u64), Reference($t0))} fun TestBorrow::test9[baseline] -borrowed_by: Reference($t1) -> {(.x (u64), Return(0)), (.y (u64), Return(0))} -borrows_from: Return(0) -> {(.x (u64), Reference($t1)), (.y (u64), Reference($t1))} +borrowed_by: Reference($t1) -> {(.y (u64), Return(0)), (.x (u64)/@, Return(0))} +borrows_from: Return(0) -> {(.y (u64), Reference($t1)), (.x (u64)/@, Reference($t1))} diff --git a/language/move-prover/bytecode/tests/memory_instr/basic_test.exp b/language/move-prover/bytecode/tests/memory_instr/basic_test.exp index ecec245e94..10f040b31e 100644 --- a/language/move-prover/bytecode/tests/memory_instr/basic_test.exp +++ b/language/move-prover/bytecode/tests/memory_instr/basic_test.exp @@ -358,34 +358,39 @@ fun TestPackref::test7($t0|b: bool) { var $t5: u64 var $t6: &mut TestPackref::R var $t7: u64 + var $t8: bool 0: $t4 := 3 1: $t1 := pack TestPackref::R($t4) 2: $t5 := 4 3: $t2 := pack TestPackref::R($t5) 4: $t6 := borrow_local($t1) 5: $t3 := $t6 - 6: write_back[LocalRoot($t1)@]($t6) - 7: trace_local[r1]($t1) - 8: if ($t0) goto 20 else goto 25 - 9: label L0 + 6: if ($t0) goto 25 else goto 29 + 7: label L0 + 8: write_back[LocalRoot($t1)@]($t6) + 9: trace_local[r1]($t1) 10: destroy($t6) 11: $t3 := borrow_local($t2) 12: label L2 13: $t7 := 0 14: TestPackref::test3($t3, $t7) - 15: write_back[LocalRoot($t1)@]($t3) - 16: trace_local[r1]($t1) - 17: write_back[LocalRoot($t2)@]($t3) - 18: trace_local[r2]($t2) - 19: return () - 20: label L3 - 21: write_back[LocalRoot($t1)@]($t3) + 15: write_back[LocalRoot($t2)@]($t3) + 16: trace_local[r2]($t2) + 17: $t8 := is_parent[Reference($t6)@]($t3) + 18: if ($t8) goto 19 else goto 23 + 19: label L5 + 20: write_back[Reference($t6)@]($t3) + 21: write_back[LocalRoot($t1)@]($t6) 22: trace_local[r1]($t1) - 23: destroy($t3) - 24: goto 9 - 25: label L4 - 26: destroy($t6) - 27: goto 12 + 23: label L6 + 24: return () + 25: label L3 + 26: write_back[Reference($t6)@]($t3) + 27: destroy($t3) + 28: goto 7 + 29: label L4 + 30: destroy($t6) + 31: goto 12 } diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp new file mode 100644 index 0000000000..35773607e1 --- /dev/null +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp @@ -0,0 +1,113 @@ +Move prover returns: exiting with verification errors +error: unknown assertion failed + ┌─ tests/sources/functional/loops_with_memory_ops.move:93:13 + │ +93 │ assert forall m in 0..length: a[m] == b[m]; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = a = + = b = + = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 + = length = + = at tests/sources/functional/loops_with_memory_ops.move:59: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:60: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:62: nested_loop2 + = i = + = at tests/sources/functional/loops_with_memory_ops.move:63: nested_loop2 + = x = + = at tests/sources/functional/loops_with_memory_ops.move:64: nested_loop2 + = y = + = at tests/sources/functional/loops_with_memory_ops.move:66: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:69: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:70: nested_loop2 + = enter loop, variable(s) a, b, i, x, y havocked and reassigned + = a = + = b = + = i = + = x = + = y = + = loop invariant holds at current state + = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:69: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:70: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:73: nested_loop2 + = enter loop, variable(s) x, y havocked and reassigned + = x = + = y = + = at tests/sources/functional/loops_with_memory_ops.move:74: nested_loop2 + = enter loop, variable(s) y havocked and reassigned + = y = + = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = b = + = b = + = a = + = a = + = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 + = i = + = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:93: nested_loop2 + +error: induction case of the loop invariant does not hold + ┌─ tests/sources/functional/loops_with_memory_ops.move:70:17 + │ +70 │ invariant forall n in 0..i: a[n] == b[n]; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = a = + = b = + = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 + = length = + = at tests/sources/functional/loops_with_memory_ops.move:59: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:60: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:62: nested_loop2 + = i = + = at tests/sources/functional/loops_with_memory_ops.move:63: nested_loop2 + = x = + = at tests/sources/functional/loops_with_memory_ops.move:64: nested_loop2 + = y = + = at tests/sources/functional/loops_with_memory_ops.move:66: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:69: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:70: nested_loop2 + = enter loop, variable(s) a, b, i, x, y havocked and reassigned + = a = + = b = + = i = + = x = + = y = + = loop invariant holds at current state + = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:69: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:70: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:73: nested_loop2 + = enter loop, variable(s) x, y havocked and reassigned + = x = + = y = + = at tests/sources/functional/loops_with_memory_ops.move:74: nested_loop2 + = enter loop, variable(s) y havocked and reassigned + = y = + = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = b = + = b = + = a = + = a = + = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 + = i = + = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:89: nested_loop2 + = x = + = at tests/sources/functional/loops_with_memory_ops.move:90: nested_loop2 + = y = + = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:69: nested_loop2 + = at tests/sources/functional/loops_with_memory_ops.move:70: nested_loop2 diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp index 7a0a342456..bdf5525e71 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp @@ -15,10 +15,8 @@ error: unknown assertion failed = at tests/sources/functional/loops_with_memory_ops.move:62: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:63: nested_loop2 - = a = = x = = at tests/sources/functional/loops_with_memory_ops.move:64: nested_loop2 - = b = = y = = at tests/sources/functional/loops_with_memory_ops.move:66: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 @@ -45,8 +43,13 @@ error: unknown assertion failed = y = = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = - = a = + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 @@ -68,10 +71,8 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops_with_memory_ops.move:62: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:63: nested_loop2 - = a = = x = = at tests/sources/functional/loops_with_memory_ops.move:64: nested_loop2 - = b = = y = = at tests/sources/functional/loops_with_memory_ops.move:66: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 @@ -98,16 +99,20 @@ error: induction case of the loop invariant does not hold = y = = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = b = - = a = + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:89: nested_loop2 - = a = = x = = at tests/sources/functional/loops_with_memory_ops.move:90: nested_loop2 - = b = = y = = at tests/sources/functional/loops_with_memory_ops.move:67: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:68: nested_loop2 diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.move b/language/move-prover/tests/sources/functional/loops_with_memory_ops.move index dd858d320f..9badb37647 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.move +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.move @@ -1,5 +1,5 @@ +// separate_baseline: cvc5 module 0x42::VerifyLoopsWithMemoryOps { - use std::vector; spec module { pragma verify=true; diff --git a/language/move-prover/tests/sources/functional/mut_ref_arg_return.move b/language/move-prover/tests/sources/functional/mut_ref_arg_return.move new file mode 100644 index 0000000000..70bc9f80bc --- /dev/null +++ b/language/move-prover/tests/sources/functional/mut_ref_arg_return.move @@ -0,0 +1,36 @@ +module 0x42::Test { + // test case 1 + fun one_of_two(cond: bool, r1: &mut u64, r2: &mut u64): &mut u64 { + if (cond) {r1} else {r2} + } + + fun test1(cond: bool, v1: u64, v2: u64) { + let r = one_of_two(cond, &mut v1, &mut v2); + *r = 0; + + spec { + assert cond ==> v1 == 0; + assert !cond ==> v2 == 0; + } + } + + // test case 2 + fun max_mut(ma: &mut u64, mb: &mut u64): &mut u64 { + if (*ma >= *mb) { + ma + } else { + mb + } + } + + fun test2(a: u64, b: u64) { + let mc = max_mut(&mut a, &mut b); + *mc = *mc + 7; + + spec { + assert a != b; + assert (a > b) ==> (a - b >= 7); + assert (a < b) ==> (b - a >= 7); + } + } +} From 7d28bfa484ef7d9ff225a748832de1cf1b67d77b Mon Sep 17 00:00:00 2001 From: vgao Date: Tue, 26 Jul 2022 22:03:36 -0700 Subject: [PATCH 009/169] [stdlib] make fields of GasParameters public --- language/move-stdlib/src/natives/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/language/move-stdlib/src/natives/mod.rs b/language/move-stdlib/src/natives/mod.rs index d2b9655670..45badf66cd 100644 --- a/language/move-stdlib/src/natives/mod.rs +++ b/language/move-stdlib/src/natives/mod.rs @@ -21,14 +21,14 @@ use move_vm_runtime::native_functions::{make_table_from_iter, NativeFunctionTabl #[derive(Debug, Clone)] pub struct GasParameters { - bcs: bcs::GasParameters, - hash: hash::GasParameters, - signer: signer::GasParameters, - string: string::GasParameters, - vector: vector::GasParameters, + pub bcs: bcs::GasParameters, + pub hash: hash::GasParameters, + pub signer: signer::GasParameters, + pub string: string::GasParameters, + pub vector: vector::GasParameters, #[cfg(feature = "testing")] - unit_test: unit_test::GasParameters, + pub unit_test: unit_test::GasParameters, } impl GasParameters { From 849e356e9307c2489024008f4c91c86f721b13da Mon Sep 17 00:00:00 2001 From: "Kaiwen (Chloe) Chen" <35128156+ckaiwxm@users.noreply.github.com> Date: Wed, 27 Jul 2022 17:41:23 -0400 Subject: [PATCH 010/169] [move-prover] Add evaluation logic for choice operators (#311) * [move-prover] add unit test for choice operators * [move-prover] complete the evaluator for choice operators Store all the satisfied values for choice operators and use determinate method to choose the value stored at the last position as the result In particular, this PR - Complete the evaluator for the choose and choose min operators. All the values in the range that satisfy the predicate are extracted and the value in the last position of the vector is returned deterministically for the `choose` operator. - Update the evaluator for assume expression to return `EvalResult` to distinguish `None` results from `choice` operators and other assertions. - Move `skip_specs` from the function context to the local state to handle the evaluation process when a `let` binding fails, i.e., when the `choice` operators return `None`, skip the following specs to log the error message. - When no value satisfies the predicate for the `choice` operators, log the error message in the end. Co-authored-by: Kaiwen Chen --- .../tests/concrete_check/choice.exp | 67 +++++++++++++++++++ .../tests/concrete_check/choice.move | 58 ++++++++++++++++ .../tests/concrete_check/quantifier.move | 2 +- .../interpreter/src/concrete/evaluator.rs | 59 +++++++++++++--- .../interpreter/src/concrete/local_state.rs | 15 ++++- .../interpreter/src/concrete/player.rs | 48 ++++++------- 6 files changed, 214 insertions(+), 35 deletions(-) create mode 100644 language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp create mode 100644 language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp new file mode 100644 index 0000000000..e7da95feb6 --- /dev/null +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp @@ -0,0 +1,67 @@ +Running Move unit tests +[ FAIL ] 0x2::A::simple_number_min_range_failure +[ FAIL ] 0x2::A::simple_number_range_failure +[ FAIL ] 0x2::A::vector_choose_min_unsatisfied_predicate +[ PASS ] 0x2::A::vector_choose_success +[ FAIL ] 0x2::A::vector_choose_unsatisfied_predicate + +Test failures: + +Failures in 0x2::A: + +┌── simple_number_min_range_failure ────── +│ error: failed to evaluate expression: enumeration of a non-address type domain is not supported +│ ┌─ tests/concrete_check/choice.move:56:42 +│ │ +│ 56 │ ensures result <= (choose min x: u64 where x >= 4); +│ │ ^^^ +│ +│ error: failed to evaluate expression: unexpected error code +│ ┌─ tests/concrete_check/choice.move:56:17 +│ │ +│ 56 │ ensures result <= (choose min x: u64 where x >= 4); +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ +│ +└────────────────── + + +┌── simple_number_range_failure ────── +│ error: failed to evaluate expression: enumeration of a non-address type domain is not supported +│ ┌─ tests/concrete_check/choice.move:49:38 +│ │ +│ 49 │ ensures result <= (choose x: u64 where x >= 4); +│ │ ^^^ +│ +│ error: failed to evaluate expression: unexpected error code +│ ┌─ tests/concrete_check/choice.move:49:17 +│ │ +│ 49 │ ensures result <= (choose x: u64 where x >= 4); +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ +│ +└────────────────── + + +┌── vector_choose_min_unsatisfied_predicate ────── +│ error: failed to evaluate expression: choose min fails to satisfy a predicate +│ ┌─ tests/concrete_check/choice.move:42:68 +│ │ +│ 42 │ let post choice_min = choose min i in 0..len(result) where result[i] == 3; +│ │ ^^^^^^^^^^^^^^ +│ +│ +└────────────────── + + +┌── vector_choose_unsatisfied_predicate ────── +│ error: failed to evaluate expression: choose fails to satisfy a predicate +│ ┌─ tests/concrete_check/choice.move:29:60 +│ │ +│ 29 │ let post choice = choose i in 0..len(result) where result[i] == 3; +│ │ ^^^^^^^^^^^^^^ +│ +│ +└────────────────── + +Test result: FAILED. Total tests: 5; passed: 1; failed: 4 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move new file mode 100644 index 0000000000..030bfa1bfc --- /dev/null +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move @@ -0,0 +1,58 @@ +module 0x2::A { + use std::vector; + + #[test] + public fun vector_choose_success(): vector { + let v = vector::empty(); + vector::push_back(&mut v, 1); + vector::push_back(&mut v, 2); + vector::push_back(&mut v, 1); + v + } + + spec vector_choose_success { + let post choice = choose i in 0..len(result) where result[i] == 1; + ensures choice == 0 || choice == 2; + ensures (choose min i in 0..len(result) where result[i] == 1) == 0; + } + + #[test] + public fun vector_choose_unsatisfied_predicate(): vector { + let v = vector::empty(); + vector::push_back(&mut v, 1); + vector::push_back(&mut v, 2); + vector::push_back(&mut v, 1); + v + } + + spec vector_choose_unsatisfied_predicate { + let post choice = choose i in 0..len(result) where result[i] == 3; + } + + #[test] + public fun vector_choose_min_unsatisfied_predicate(): vector { + let v = vector::empty(); + vector::push_back(&mut v, 1); + vector::push_back(&mut v, 2); + vector::push_back(&mut v, 1); + v + } + + spec vector_choose_min_unsatisfied_predicate { + let post choice_min = choose min i in 0..len(result) where result[i] == 3; + } + + #[test] + public fun simple_number_range_failure(): u64 { 1 } + + spec simple_number_range_failure { + ensures result <= (choose x: u64 where x >= 4); + } + + #[test] + public fun simple_number_min_range_failure(): u64 { 1 } + + spec simple_number_min_range_failure { + ensures result <= (choose min x: u64 where x >= 4); + } +} diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/quantifier.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/quantifier.move index f8e8eb683d..985cf03d6f 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/quantifier.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/quantifier.move @@ -31,7 +31,7 @@ module 0x2::A { ensures exists i in 0..len(result): result[i] == 1; } - #[test, expected_failure] + #[test] public fun init_vector_failure(): vector { let v = vector::empty(); vector::push_back(&mut v, 1); diff --git a/language/move-prover/interpreter/src/concrete/evaluator.rs b/language/move-prover/interpreter/src/concrete/evaluator.rs index 80c6acaca1..fc747fc032 100644 --- a/language/move-prover/interpreter/src/concrete/evaluator.rs +++ b/language/move-prover/interpreter/src/concrete/evaluator.rs @@ -142,7 +142,7 @@ impl<'env> Evaluator<'env> { /// Check whether an assume expression holds, unless the assume expression represents a `let` /// binding. In that case, return the `TypedValue` of the let-binding as well as the local /// variable (index) the value should bind to. - pub fn check_assume(&self, exp: &Exp) -> Option<(TempIndex, TypedValue)> { + pub fn check_assume(&self, exp: &Exp) -> Option> { // NOTE: `let` bindings are translated to `Assume(Identical($t, ));`. This should be // treated as an assignment. if let ExpData::Call(_, Operation::Identical, args) = exp.as_ref() { @@ -164,8 +164,10 @@ impl<'env> Evaluator<'env> { self.local_state.get_type(local_idx).get_base_type() ); } - let local_val = self.evaluate(&args[1]).unwrap(); - Some((local_idx, TypedValue::fuse_base(local_ty, local_val))) + match self.evaluate(&args[1]) { + Ok(val) => Some(Ok((local_idx, TypedValue::fuse_base(local_ty, val)))), + Err(err) => Some(Err(err)), + } } else { // for all other cases, treat with as an assertion self.check_assert(exp); @@ -651,6 +653,13 @@ impl<'env> Evaluator<'env> { let r_vals = self.prepare_range(r_exp)?; vals_vec.push(r_vals); } + let choose_val_range = match kind { + QuantKind::Forall | QuantKind::Exists => None, + QuantKind::Choose | QuantKind::ChooseMin => { + assert_eq!(vals_vec.len(), 1); + Some(vals_vec[0].clone()) + } + }; let mut loop_results = vec![]; for val_vec in vals_vec.into_iter().multi_cartesian_product() { @@ -682,19 +691,49 @@ impl<'env> Evaluator<'env> { } } - let quant_result = match kind { + match kind { QuantKind::Forall => { let v = loop_results.into_iter().all(|r| r.into_bool()); - BaseValue::mk_bool(v) + let quant_result = BaseValue::mk_bool(v); + Ok(quant_result) } QuantKind::Exists => { let v = loop_results.into_iter().any(|r| r.into_bool()); - BaseValue::mk_bool(v) + let quant_result = BaseValue::mk_bool(v); + Ok(quant_result) } - // TODO (mengxu) support choose operators - QuantKind::Choose | QuantKind::ChooseMin => unimplemented!(), - }; - Ok(quant_result) + QuantKind::Choose => { + let choose_val_range_vec = choose_val_range.unwrap(); + let mut v_results: Vec<_> = choose_val_range_vec + .into_iter() + .zip(loop_results.into_iter()) + .filter_map(|(val, r)| if r.into_bool() { Some(val) } else { None }) + .collect(); + + match v_results.pop() { + None => { + self.record_evaluation_failure(body, "choose fails to satisfy a predicate"); + Err(Self::eval_failure_code()) + } + Some(v) => Ok(v), + } + } + QuantKind::ChooseMin => { + let choose_val_range_vec = choose_val_range.unwrap(); + let mut v_results: Vec<_> = choose_val_range_vec + .into_iter() + .zip(loop_results.into_iter()) + .filter_map(|(val, r)| if r.into_bool() { Some(val) } else { None }) + .collect(); + + if v_results.is_empty() { + self.record_evaluation_failure(body, "choose min fails to satisfy a predicate"); + Err(Self::eval_failure_code()) + } else { + Ok(v_results.remove(0)) + } + } + } } // diff --git a/language/move-prover/interpreter/src/concrete/local_state.rs b/language/move-prover/interpreter/src/concrete/local_state.rs index cec52f03e7..3bbbdc5330 100644 --- a/language/move-prover/interpreter/src/concrete/local_state.rs +++ b/language/move-prover/interpreter/src/concrete/local_state.rs @@ -69,16 +69,19 @@ pub struct LocalState { termination: TerminationStatus, /// mutable parameters that gets destroyed during the execution destroyed_args: BTreeMap, + /// whether specification checking needs to be skipped + skip_specs: bool, } impl LocalState { - pub fn new(slots: Vec) -> Self { + pub fn new(slots: Vec, skip_specs: bool) -> Self { Self { slots, pc: 0, pc_branch: false, termination: TerminationStatus::None, destroyed_args: BTreeMap::new(), + skip_specs, } } @@ -208,4 +211,14 @@ impl LocalState { pub fn into_termination_status(self) -> TerminationStatus { self.termination } + + /// Mark the spec checking disabled for the rest of the function + pub fn skip_specs(&mut self) { + self.skip_specs = true; + } + + /// Check whether we are skipping the specs + pub fn is_spec_skipped(&self) -> bool { + self.skip_specs + } } diff --git a/language/move-prover/interpreter/src/concrete/player.rs b/language/move-prover/interpreter/src/concrete/player.rs index 35961145e9..d03dbec6ef 100644 --- a/language/move-prover/interpreter/src/concrete/player.rs +++ b/language/move-prover/interpreter/src/concrete/player.rs @@ -71,7 +71,6 @@ pub struct FunctionContext<'env> { holder: &'env FunctionTargetsHolder, target: FunctionTarget<'env>, ty_args: Vec, - skip_specs: bool, label_offsets: BTreeMap, // debug level: usize, @@ -82,7 +81,6 @@ impl<'env> FunctionContext<'env> { holder: &'env FunctionTargetsHolder, target: FunctionTarget<'env>, ty_args: Vec, - skip_specs: bool, level: usize, ) -> Self { let label_offsets = Bytecode::label_offsets(target.get_bytecode()); @@ -90,7 +88,6 @@ impl<'env> FunctionContext<'env> { holder, target, ty_args, - skip_specs, label_offsets, level, } @@ -115,13 +112,14 @@ impl<'env> FunctionContext<'env> { /// Execute a user function with value arguments. pub fn exec_user_function( &self, + skip_specs: bool, typed_args: Vec, global_state: &mut GlobalState, eval_state: &mut EvalState, ) -> ExecResult { let instructions = self.target.get_bytecode(); let debug_bytecode = self.get_settings().verbose_bytecode; - let mut local_state = self.prepare_local_state(typed_args); + let mut local_state = self.prepare_local_state(skip_specs, typed_args); while !local_state.is_terminated() { let pc = local_state.get_pc() as usize; let bytecode = instructions.get(pc).unwrap(); @@ -147,7 +145,7 @@ impl<'env> FunctionContext<'env> { local_state: &mut LocalState, global_state: &mut GlobalState, ) -> ExecResult> { - let mut dummy_state = self.prepare_local_state(typed_args); + let mut dummy_state = self.prepare_local_state(local_state.is_spec_skipped(), typed_args); if cfg!(debug_assertions) { assert_eq!(dummy_state.num_slots(), srcs.len()); } @@ -359,13 +357,13 @@ impl<'env> FunctionContext<'env> { eval_state, ), Bytecode::Prop(_, PropKind::Assert, exp) => { - if !self.skip_specs { + if !local_state.is_spec_skipped() { self.handle_prop_assert(exp, eval_state, local_state, global_state) } } Bytecode::Prop(_, PropKind::Assume, exp) => { - if !self.skip_specs { - self.handle_prop_assume(exp, eval_state, local_state, global_state) + if !local_state.is_spec_skipped() { + self.handle_prop_assume(exp, eval_state, local_state, global_state)? } } // expressions (TODO: not supported yet) @@ -940,8 +938,12 @@ impl<'env> FunctionContext<'env> { .collect(); // execute the user function - let mut callee_state = - callee_ctxt.exec_user_function(typed_args, global_state, eval_state)?; + let mut callee_state = callee_ctxt.exec_user_function( + local_state.is_spec_skipped(), + typed_args, + global_state, + eval_state, + )?; // update mutable arguments for (callee_idx, origin_idx) in mut_args { @@ -1847,7 +1849,7 @@ impl<'env> FunctionContext<'env> { eval_state: &EvalState, local_state: &mut LocalState, global_state: &GlobalState, - ) { + ) -> ExecResult<()> { let evaluator = Evaluator::new( self.holder, &self.target, @@ -1861,10 +1863,15 @@ impl<'env> FunctionContext<'env> { match evaluator.check_assume(exp) { None => (), // handle let-bindings - Some((local_idx, local_val)) => { + Some(Ok((local_idx, local_val))) => { local_state.put_value_override(local_idx, local_val); } + Some(Err(_)) => { + // unable to find a satisfiable value for a let-binding + local_state.skip_specs(); + } } + Ok(()) } // @@ -2188,16 +2195,10 @@ impl<'env> FunctionContext<'env> { .collect(); // build the context - FunctionContext::new( - self.holder, - callee_target, - callee_ty_insts, - self.skip_specs, - self.level + 1, - ) + FunctionContext::new(self.holder, callee_target, callee_ty_insts, self.level + 1) } - fn prepare_local_state(&self, typed_args: Vec) -> LocalState { + fn prepare_local_state(&self, skip_specs: bool, typed_args: Vec) -> LocalState { let target = &self.target; let env = target.global_env(); @@ -2241,7 +2242,7 @@ impl<'env> FunctionContext<'env> { let slot = LocalSlot::new_tmp(name, ty); local_slots.push(slot); } - LocalState::new(local_slots) + LocalState::new(local_slots, skip_specs) } } @@ -2260,8 +2261,9 @@ pub fn entrypoint( global_state: &mut GlobalState, ) -> ExecResult> { let mut eval_state = EvalState::default(); - let ctxt = FunctionContext::new(holder, target, ty_args.to_vec(), skip_specs, level); - let local_state = ctxt.exec_user_function(typed_args, global_state, &mut eval_state)?; + let ctxt = FunctionContext::new(holder, target, ty_args.to_vec(), level); + let local_state = + ctxt.exec_user_function(skip_specs, typed_args, global_state, &mut eval_state)?; let termination = local_state.into_termination_status(); match termination { TerminationStatus::Abort(abort_info) => Err(abort_info), From 55a40d583dddd5c1e529db6503dc88a189307cdf Mon Sep 17 00:00:00 2001 From: Ville Sundell Date: Thu, 28 Jul 2022 21:13:08 +0300 Subject: [PATCH 011/169] [move-cli] Added "docgen" command (#291) * [move-cli] Added "docgen" command Move Prover's "--docgen" switch is not currently exposed to the user, so added a top level command "docgen" to do the trick. Also forwarding --docgen-template if needed, and implemented a new switch --quiet mainly for test setups where output must be deterministic. The --docgen-template switch is currently the only Docgen related option switch exposed to the user by the Prover. Move Prover is also mentioned in the description, so the user knows they must have a working Move Prover setup in order to use this feature. * [move-cli] Added a test for "docgen" command Added a simple test for the new "move docgen" command. We are testing a simple document generation with a simple template, supressing the output for testing purposes (with the --quiet switch). --- language/tools/move-cli/src/base/docgen.rs | 48 +++++++++++++++++++ language/tools/move-cli/src/base/mod.rs | 1 + language/tools/move-cli/src/lib.rs | 6 ++- .../simple_build_with_docs/args.exp | 9 ++++ .../simple_build_with_docs/args.txt | 5 ++ .../simple_build_with_docs/sources/Foo.move | 5 ++ .../simple_build_with_docs/template.md | 1 + 7 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 language/tools/move-cli/src/base/docgen.rs create mode 100644 language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.exp create mode 100644 language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.txt create mode 100644 language/tools/move-cli/tests/build_tests/simple_build_with_docs/sources/Foo.move create mode 100644 language/tools/move-cli/tests/build_tests/simple_build_with_docs/template.md diff --git a/language/tools/move-cli/src/base/docgen.rs b/language/tools/move-cli/src/base/docgen.rs new file mode 100644 index 0000000000..882e39a734 --- /dev/null +++ b/language/tools/move-cli/src/base/docgen.rs @@ -0,0 +1,48 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::base::prove::{Prove, ProverOptions}; +use clap::*; +use move_package::BuildConfig; +use std::path::PathBuf; + +/// Generating javadoc style documentation for packages using the Move Prover +#[derive(Parser)] +#[clap(name = "docgen")] +pub struct Docgen { + /// Do not print out other than errors + #[clap(long = "quiet", short = 'q')] + pub quiet: bool, + /// A template for documentation generation. + #[clap(long = "template", short = 't', value_name = "FILE")] + pub template: Option, +} + +impl Docgen { + /// Simply calling the Move Prover with "--docgen" + /// Forwarding `--docgen-template` and setting `--verbose` to `error` if applicable + pub fn execute(self, path: Option, config: BuildConfig) -> anyhow::Result<()> { + let mut options_list = vec!["--docgen".to_string()]; + + if self.quiet { + options_list.push("--verbose".to_string()); + options_list.push("error".to_string()); + } + if self.template.is_some() { + options_list.push("--docgen-template".to_string()); + options_list.push(self.template.unwrap()); + } + + let options = Some(ProverOptions::Options(options_list)); + + Prove::execute( + Prove { + target_filter: None, + for_test: false, + options, + }, + path, + config, + ) + } +} diff --git a/language/tools/move-cli/src/base/mod.rs b/language/tools/move-cli/src/base/mod.rs index f0583c21a4..0633fcc2dd 100644 --- a/language/tools/move-cli/src/base/mod.rs +++ b/language/tools/move-cli/src/base/mod.rs @@ -4,6 +4,7 @@ pub mod build; pub mod coverage; pub mod disassemble; +pub mod docgen; pub mod errmap; pub mod info; pub mod new; diff --git a/language/tools/move-cli/src/lib.rs b/language/tools/move-cli/src/lib.rs index 8c305af1ad..e3206a904c 100644 --- a/language/tools/move-cli/src/lib.rs +++ b/language/tools/move-cli/src/lib.rs @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 use base::{ - build::Build, coverage::Coverage, disassemble::Disassemble, errmap::Errmap, info::Info, - new::New, prove::Prove, test::Test, + build::Build, coverage::Coverage, disassemble::Disassemble, docgen::Docgen, errmap::Errmap, + info::Info, new::New, prove::Prove, test::Test, }; use move_package::BuildConfig; @@ -65,6 +65,7 @@ pub enum Command { Build(Build), Coverage(Coverage), Disassemble(Disassemble), + Docgen(Docgen), Errmap(Errmap), Info(Info), New(New), @@ -106,6 +107,7 @@ pub fn run_cli( Command::Build(c) => c.execute(move_args.package_path, move_args.build_config), Command::Coverage(c) => c.execute(move_args.package_path, move_args.build_config), Command::Disassemble(c) => c.execute(move_args.package_path, move_args.build_config), + Command::Docgen(c) => c.execute(move_args.package_path, move_args.build_config), Command::Errmap(c) => c.execute(move_args.package_path, move_args.build_config), Command::Info(c) => c.execute(move_args.package_path, move_args.build_config), Command::New(c) => c.execute_with_defaults(move_args.package_path), diff --git a/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.exp b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.exp new file mode 100644 index 0000000000..eb08bbb6ab --- /dev/null +++ b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.exp @@ -0,0 +1,9 @@ +Command `new --path . Foo`: +Command `build`: +INCLUDING DEPENDENCY MoveStdlib +BUILDING Foo +Command `docgen --quiet --template template.md`: +External Command `grep documentation doc/Foo.md`: +Test documentation comment +External Command `cat doc/template.md`: +This is a test template diff --git a/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.txt b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.txt new file mode 100644 index 0000000000..713fd541a5 --- /dev/null +++ b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/args.txt @@ -0,0 +1,5 @@ +new --path . Foo +build +docgen --quiet --template template.md +> grep documentation doc/Foo.md +> cat doc/template.md diff --git a/language/tools/move-cli/tests/build_tests/simple_build_with_docs/sources/Foo.move b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/sources/Foo.move new file mode 100644 index 0000000000..6af3654843 --- /dev/null +++ b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/sources/Foo.move @@ -0,0 +1,5 @@ +module 0x1::Foo { + /// Test documentation comment + public fun foo() { + } +} diff --git a/language/tools/move-cli/tests/build_tests/simple_build_with_docs/template.md b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/template.md new file mode 100644 index 0000000000..a9130f91a8 --- /dev/null +++ b/language/tools/move-cli/tests/build_tests/simple_build_with_docs/template.md @@ -0,0 +1 @@ +This is a test template From d80b85749e378617b30c7fbe494f4fd804381ac9 Mon Sep 17 00:00:00 2001 From: 0xbe1 <101405096+0xbe1@users.noreply.github.com> Date: Fri, 29 Jul 2022 05:05:02 +0800 Subject: [PATCH 012/169] Fix typo (#313) --- language/documentation/tutorial/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/tutorial/README.md b/language/documentation/tutorial/README.md index 55c09debc8..7eb7464a2a 100644 --- a/language/documentation/tutorial/README.md +++ b/language/documentation/tutorial/README.md @@ -571,7 +571,7 @@ source ~/.profile ``` ## Step 7: Use the Move prover -Smart contracts deployed on the blockchain may maniputate high-value assets. As a technique that uses strict +Smart contracts deployed on the blockchain may manipulate high-value assets. As a technique that uses strict mathematical methods to describe behavior and reason correctness of computer systems, formal verification has been used in blockchains to prevent bugs in smart contracts. [ The Move prover](https://github.com/move-language/move/blob/main/language/move-prover/doc/user/prover-guide.md) From 081abec6ba7a93d6b5b6068d3759d103b63d8c39 Mon Sep 17 00:00:00 2001 From: 0xbe1 <101405096+0xbe1@users.noreply.github.com> Date: Fri, 29 Jul 2022 05:05:08 +0800 Subject: [PATCH 013/169] fix tutorial step_5 comment (#315) --- .../tutorial/step_5/BasicCoin/sources/BasicCoin.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move b/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move index 488c3ba2d4..1b4a1a437b 100644 --- a/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move +++ b/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move @@ -97,7 +97,7 @@ module NamedAddr::BasicCoin { publish_balance(&account); } - // EXERCISE: Write `balance_dne` test here! + // EXERCISE: Write `balance_of_dne` test here! #[test] #[expected_failure] From d9ee383b320e3cd60de043e1c93e4315e779835a Mon Sep 17 00:00:00 2001 From: 0xbe1 <101405096+0xbe1@users.noreply.github.com> Date: Fri, 29 Jul 2022 05:05:13 +0800 Subject: [PATCH 014/169] fix tutorial tests (#314) --- .../tutorial/step_5/BasicCoin/sources/BasicCoin.move | 2 +- .../tutorial/step_5_sol/BasicCoin/sources/BasicCoin.move | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move b/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move index 1b4a1a437b..f901557178 100644 --- a/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move +++ b/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move @@ -91,7 +91,7 @@ module NamedAddr::BasicCoin { } #[test(account = @0x1)] - #[expected_failure(abort_code = 518)] // Can specify an abort code + #[expected_failure(abort_code = 2)] // Can specify an abort code fun publish_balance_already_exists(account: signer) { publish_balance(&account); publish_balance(&account); diff --git a/language/documentation/tutorial/step_5_sol/BasicCoin/sources/BasicCoin.move b/language/documentation/tutorial/step_5_sol/BasicCoin/sources/BasicCoin.move index 496c7721af..a6e31ba552 100644 --- a/language/documentation/tutorial/step_5_sol/BasicCoin/sources/BasicCoin.move +++ b/language/documentation/tutorial/step_5_sol/BasicCoin/sources/BasicCoin.move @@ -91,7 +91,7 @@ module NamedAddr::BasicCoin { } #[test(account = @0x1)] - #[expected_failure(abort_code = 518)] // Can specify an abort code + #[expected_failure(abort_code = 2)] // Can specify an abort code fun publish_balance_already_exists(account: signer) { publish_balance(&account); publish_balance(&account); From 4f8b28a6c3ac937b4f7ae134e04142edebbf8f0a Mon Sep 17 00:00:00 2001 From: Greg Nazario Date: Thu, 28 Jul 2022 23:09:29 -0700 Subject: [PATCH 015/169] Use standard traits for FromStr (#317) * [language-storage] Implement FromStr for TypeTag and StructTag * [account-address] Allow 0xHEX or HEX to be parsed as an account address --- .../move-core/types/src/account_address.rs | 7 +++++- .../move-core/types/src/language_storage.rs | 23 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/language/move-core/types/src/account_address.rs b/language/move-core/types/src/account_address.rs index 117fbc8541..d09bff6c39 100644 --- a/language/move-core/types/src/account_address.rs +++ b/language/move-core/types/src/account_address.rs @@ -223,7 +223,12 @@ impl FromStr for AccountAddress { type Err = AccountAddressParseError; fn from_str(s: &str) -> Result { - Self::from_hex(s) + // Accept 0xADDRESS or ADDRESS + if let Ok(address) = AccountAddress::from_hex_literal(s) { + Ok(address) + } else { + Self::from_hex(s) + } } } diff --git a/language/move-core/types/src/language_storage.rs b/language/move-core/types/src/language_storage.rs index 72f168f0da..c09f39bb27 100644 --- a/language/move-core/types/src/language_storage.rs +++ b/language/move-core/types/src/language_storage.rs @@ -5,11 +5,15 @@ use crate::{ account_address::AccountAddress, identifier::{IdentStr, Identifier}, + parser::{parse_struct_tag, parse_type_tag}, }; #[cfg(any(test, feature = "fuzzing"))] use proptest_derive::Arbitrary; use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter}; +use std::{ + fmt::{Display, Formatter}, + str::FromStr, +}; pub const CODE_TAG: u8 = 0; pub const RESOURCE_TAG: u8 = 1; @@ -38,12 +42,19 @@ pub enum TypeTag { Struct(StructTag), } +impl FromStr for TypeTag { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + parse_type_tag(s) + } +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)] pub struct StructTag { pub address: AccountAddress, pub module: Identifier, pub name: Identifier, - // TODO: rename to "type_args" (or better "ty_args"?) // alias for compatibility with old json serialized data. #[serde(rename = "type_args", alias = "type_params")] pub type_params: Vec, @@ -61,6 +72,14 @@ impl StructTag { } } +impl FromStr for StructTag { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + parse_struct_tag(s) + } +} + /// Represents the intitial key into global storage where we first index by the address, and then /// the struct tag #[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)] From 0fda31b261f3b9ef086e6202cd11e27b4c430fa5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 29 Jul 2022 18:43:45 -0700 Subject: [PATCH 016/169] Fix broken test code in readme (#316) --- language/documentation/tutorial/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/tutorial/README.md b/language/documentation/tutorial/README.md index 7eb7464a2a..5eb2a41f71 100644 --- a/language/documentation/tutorial/README.md +++ b/language/documentation/tutorial/README.md @@ -232,7 +232,7 @@ module 0xCAFE::BasicCoin { // address value of `0xC0FFEE`. #[test(account = @0xC0FFEE)] fun test_mint_10(account: signer) acquires Coin { - let addr = signer::address_of(&account); + let addr = 0x1::signer::address_of(&account); mint(account, 10); // Make sure there is a `Coin` resource under `addr` with a value of `10`. // We can access this resource and its value since we are in the From e19e49a9f438c96c1a237e6729142af4f3caab20 Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Fri, 29 Jul 2022 22:35:45 -0400 Subject: [PATCH 017/169] [move-prover] multiple fixes to the memory model (#312) * [move-prover] fix is_parent tests for multiple write-back chains PR #302 has an error in terms of placing `IsParent` checks for different borrow chains. Consider the following case: ``` --borrows_from--> C A --borrows_from--> B --| --borrows_from--> D ``` When references A, B, C, D go out of scope, this will yield two chain of references: A --> B --> C and A --> B --> D This is correctly captured in #302. The bug is how to generate the `IsParent` test: The correct behavior is the following: ``` if IsParent[C](B) WriteBack[B](A) WriteBack[C](B) if IsParent[D](B) WriteBack[B](A) WriteBack[D](B) ``` i.e., branching at node B. But in #302, I mistakenly used the root of the chain as the branching point and hence, both the tests become `IsParent[B](A)`, which is not correct. This commit fixes this issue by deriving the deterministic factor for the write-back chain. Consider the case with the borrowing graph: ``` ---> E ---> C -| A ---> B -| ---> F ---> D ``` This will yield three chains: ``` if IsParent[C](B) && IsParent[E](C) WriteBack[B](A) WriteBack[C](B) WriteBack[E](C) if IsParent[C](B) && IsParent[F](C) WriteBack[B](A) WriteBack[C](B) WriteBack[F](C) if IsParent[D](B) WriteBack[B](A) WriteBack[D](B) ``` * [move-prover] improve the peephole optimization for write-back chains * [move-prover] do not peephole optimize the initial local and global borrows Live variable analysis allows the following peephole optimization: ``` $t := call(...) x := $t <$t is dead> ~~~ x := call(...) ``` This optimization makes perfect sense but unfortunately conflicts with one policy later: IsParent test can only be applied on two references: Taking the following code as an example: ``` let v1 = 0; let v2 = 0; let r = if (cond) { let r1 = &mut v1; r1 } else { let r2 = &mut v2; r2 }; ``` References `r1` and `r2` will be optimized away after the live var analysis. This leaves the reference `r` pointing to two local locations. And later when translating `IsParent` test to Boogie, we will run into cases like: ``` IsParent[LocalRoot(v1)@](r) IsParent[LocalRoot(v2)@](r) ``` And this violates our policy that IsParent can only be applied among two references. As a result, we disable this optimization for the initial local/global borrowing, which leaves the IsParent tests to be ``` IsParent[Reference(r1)@](r) IsParent[Reference(r2]@](r) ``` An alternative solution to this problem is to implement IsParent tests between a reference to a `LocalRoot` and a `GloablRoot`. But that is a more significant change and does not buy much benefits performance-wise. * [move-prover] use a special location to mark uninitialized mut refs Mutable references cannot be arbitrarily initialized, they must be initialized into a state where the IsParent test have to fail if this reference is not assigned otherwise. To be specific, consider the folowing example: ``` let v1 = 0; let v2 = 0; let r = if (cond) { let r1 = &mut v1; r1 } else { let r2 = &mut v2; r2 }; ``` This will be translated to: ``` r1 := $uninitialized(); r2 := $uninitialized(); ... ... if (cond) { r1 := borrow_local(v1); r := r1 } else { r2 := borrow_local(v2); r := r2 } ... ... if (IsParent[r1](r)) { WriteBack[r1](r); WriteBack[v1](r1); } if (IsParent[r2](r)) { WriteBack[r2](r); WriteBack[v2](r2); } ``` It is very important to mark `r1` and `r2` and `$uninitialized()` to ensure that there will be one and only one `IsParent` test activated when the write-back happens. The previous approach is to `assume IsEmptyVec(p#$Mutation($t_i));` for all `t_i` that is a mutable reference used in function locals. However, setting the `path` vector in the `Mutation` struct to zero does not guarantee that this mutation, when put under `IsParent` test, is not going to return false when that mutation is not initialized. As can be seen in the example above, even after proper assignment, `r1` and `r2` both have a `path` equal to the length of zero... (because `r` is borrowing from `r1` and `r2` `as direct borrow, not field or element borrow). This commit fixes this issue with an explicit `$Uninitialize()` constructor for the `$Location` part of a `$Mutation`. * [move-prover] use an `Uninit` operation to mark uninitialized mut refs Following from the above commit, instead of marking all mutable references in the function locals (except the function arguments) as uninitialized, this commit further restrict the number of mutable references that can be marked as `Uninit`, hence, reducing the chances of introducing inconsistent assumptions in the verification. The basic idea is to leverage the livevar analysis results, and mark whatever mutable reference that is 1) alive even before the first instruction of the function and 2) is not a parameter, as uninitialized. This commit also includes a fix to the concrete spec executor such that we do not run into errors when a mutable reference is mysterously destroyed even before it is initialized. * [move-prover] do not let bind a mutable reference for `EmitEvent` ``` public fun emit_event(handle_ref: &mut EventHandle, msg: T) { ... } ``` Events are verified in Move Prover in a special manner. One example is that the `EmitEvent` bytecode is especially designed to simulate the `emit_event` function. During the invocation of `EmitEvent`, we might be let-binding a mutable reference which we really do not want as introcuing a mutable reference via `Assume(Identical)` complicates the live var and borrow analysis (for example, we will treat the newly bounded reference as uninitialized). While essentially we do not need a reference to the handle and we can just let-bound the `$Dereference ( )` value directly, which is what is essentially done in this commit. * [move-prover] update exp files for existing tests * [move-prover] new tests to summarize the changes * [move-prover][interpreter] update the concrete semantics with direct ref borrow This re-enables the failing `if_else.move` test which conditionally (and directly) assign references to another reference. --- language/evm/move-to-yul/src/functions.rs | 1 + .../boogie-backend/src/bytecode_translator.rs | 34 +-- .../boogie-backend/src/prelude/prelude.bpl | 12 +- .../bytecode/src/borrow_analysis.rs | 11 +- .../bytecode/src/clean_and_optimize.rs | 76 +++-- .../bytecode/src/escape_analysis.rs | 3 + .../bytecode/src/function_data_builder.rs | 15 + .../bytecode/src/livevar_analysis.rs | 33 +- .../bytecode/src/memory_instrumentation.rs | 144 ++++++--- .../bytecode/src/read_write_set_analysis.rs | 3 + .../bytecode/src/spec_instrumentation.rs | 7 +- .../bytecode/src/stackless_bytecode.rs | 5 + .../src/well_formed_instrumentation.rs | 3 +- .../bytecode/tests/borrow/basic_test.exp | 282 ++++++++++-------- .../tests/borrow_strong/basic_test.exp | 282 ++++++++++-------- .../tests/memory_instr/basic_test.exp | 230 +++++++++----- .../tests/concrete_check/if_else.exp | 5 +- .../tests/concrete_check/if_else.move | 12 +- .../interpreter/src/concrete/local_state.rs | 17 +- .../interpreter/src/concrete/player.rs | 103 +++++-- .../interpreter/src/concrete/value.rs | 31 ++ .../functional/conditional_write_back.move | 31 ++ .../functional/loops_with_memory_ops.cvc5_exp | 4 + .../functional/loops_with_memory_ops.exp | 16 +- .../sources/functional/macro_verification.exp | 2 + .../tests/sources/functional/mut_ref.exp | 2 - 26 files changed, 888 insertions(+), 476 deletions(-) diff --git a/language/evm/move-to-yul/src/functions.rs b/language/evm/move-to-yul/src/functions.rs index 80a9ecd94b..4f82dc889d 100644 --- a/language/evm/move-to-yul/src/functions.rs +++ b/language/evm/move-to-yul/src/functions.rs @@ -562,6 +562,7 @@ impl<'a> FunctionGenerator<'a> { | EventStoreDiverge | OpaqueCallBegin(_, _, _) | OpaqueCallEnd(_, _, _) + | Uninit | Havoc(_) | Stop | TraceGlobalMem(_) => {} diff --git a/language/move-prover/boogie-backend/src/bytecode_translator.rs b/language/move-prover/boogie-backend/src/bytecode_translator.rs index 1277a215b3..a78b1fb304 100644 --- a/language/move-prover/boogie-backend/src/bytecode_translator.rs +++ b/language/move-prover/boogie-backend/src/bytecode_translator.rs @@ -623,13 +623,6 @@ impl<'env> FunctionTranslator<'env> { emitln!(writer, "$t{} := _$t{};", idx, idx); } - // Initialize mutations to have empty paths so $IsParentMutation works correctly. - for i in num_args..fun_target.get_local_count() { - if self.get_local_type(i).is_mutable_reference() { - emitln!(writer, "assume IsEmptyVec(p#$Mutation($t{}));", i); - } - } - // Initial assumptions if variant.is_verified() { self.translate_verify_entry_assumptions(fun_target); @@ -892,7 +885,15 @@ impl<'env> FunctionTranslator<'env> { _ => unreachable!(), }) .collect_vec(); - if edge_pattern.len() == 1 { + if edge_pattern.is_empty() { + emitln!( + writer, + "{} := $IsSameMutation({}, {});", + str_local(dests[0]), + str_local(*parent), + src_str + ); + } else if edge_pattern.len() == 1 { emitln!( writer, "{} := $IsParentMutation({}, {}, {});", @@ -1444,6 +1445,13 @@ impl<'env> FunctionTranslator<'env> { bytecode ); } + Uninit => { + emitln!( + writer, + "assume l#$Mutation($t{}) == $Uninitialized();", + srcs[0] + ); + } Destroy => {} TraceLocal(idx) => { self.track_local(*idx, srcs[0]); @@ -1456,14 +1464,6 @@ impl<'env> FunctionTranslator<'env> { EmitEvent => { let msg = srcs[0]; let handle = srcs[1]; - let translate_local = |idx: usize| { - let ty = &self.get_local_type(idx); - if ty.is_mutable_reference() { - format!("$Dereference({})", str_local(idx)) - } else { - str_local(idx) - } - }; let suffix = boogie_type_suffix(env, &self.get_local_type(msg)); emit!( writer, @@ -1471,7 +1471,7 @@ impl<'env> FunctionTranslator<'env> { if srcs.len() > 2 { "Cond" } else { "" }, suffix ); - emit!(writer, "{}, {}", translate_local(handle), str_local(msg)); + emit!(writer, "{}, {}", str_local(handle), str_local(msg)); if srcs.len() > 2 { emit!(writer, ", {}", str_local(srcs[2])); } diff --git a/language/move-prover/boogie-backend/src/prelude/prelude.bpl b/language/move-prover/boogie-backend/src/prelude/prelude.bpl index 106478a634..6127db6583 100644 --- a/language/move-prover/boogie-backend/src/prelude/prelude.bpl +++ b/language/move-prover/boogie-backend/src/prelude/prelude.bpl @@ -113,6 +113,9 @@ function {:constructor} $Local(i: int): $Location; // when mutation ends. function {:constructor} $Param(i: int): $Location; +// The location of an uninitialized mutation. Using this to make sure that the location +// will not be equal to any valid mutation locations, i.e., $Local, $Global, or $Param. +function {:constructor} $Uninitialized(): $Location; // A mutable reference which also carries its current value. Since mutable references // are single threaded in Move, we can keep them together and treat them as a value @@ -144,7 +147,12 @@ function {:inline} $ChildMutation(m: $Mutation T1, offset: int, v: T2): $Mutation(l#$Mutation(m), ExtendVec(p#$Mutation(m), offset), v) } -// Return true of the mutation is a parent of a child which was derived with the given edge offset. This +// Return true if two mutations share the location and path +function {:inline} $IsSameMutation(parent: $Mutation T1, child: $Mutation T2 ): bool { + l#$Mutation(parent) == l#$Mutation(child) && p#$Mutation(parent) == p#$Mutation(child) +} + +// Return true if the mutation is a parent of a child which was derived with the given edge offset. This // is used to implement write-back choices. function {:inline} $IsParentMutation(parent: $Mutation T1, edge: int, child: $Mutation T2 ): bool { l#$Mutation(parent) == l#$Mutation(child) && @@ -158,7 +166,7 @@ function {:inline} $IsParentMutation(parent: $Mutation T1, edge: int, ch )))) } -// Return true of the mutation is a parent of a child, for hyper edge. +// Return true if the mutation is a parent of a child, for hyper edge. function {:inline} $IsParentMutationHyper(parent: $Mutation T1, hyper_edge: Vec int, child: $Mutation T2 ): bool { l#$Mutation(parent) == l#$Mutation(child) && (var pp := p#$Mutation(parent); diff --git a/language/move-prover/bytecode/src/borrow_analysis.rs b/language/move-prover/bytecode/src/borrow_analysis.rs index 5902c0a5b5..3ba12dc4b3 100644 --- a/language/move-prover/bytecode/src/borrow_analysis.rs +++ b/language/move-prover/bytecode/src/borrow_analysis.rs @@ -23,7 +23,7 @@ use move_model::{ }; use std::{borrow::BorrowMut, collections::BTreeMap, fmt}; -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Default)] +#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd, Default)] pub struct BorrowInfo { /// Contains the nodes which are alive. This excludes nodes which are alive because /// other nodes which are alive borrow from them. @@ -41,9 +41,10 @@ pub struct BorrowInfo { } /// Represents a write-back from a source node to a destination node with the associated edge -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)] pub struct WriteBackAction { - pub src: BorrowNode, + /// the `src` of a write-back action must be a reference + pub src: TempIndex, pub dst: BorrowNode, pub edge: BorrowEdge, } @@ -116,7 +117,7 @@ impl BorrowInfo { BorrowNode::LocalRoot(..) | BorrowNode::GlobalRoot(..) => { trees.push(order); } - BorrowNode::Reference(..) => { + BorrowNode::Reference(index) => { if next.is_in_use(node) { // stop at a live reference trees.push(order); @@ -132,7 +133,7 @@ impl BorrowInfo { for (parent, edge) in incoming { let mut appended = order.clone(); appended.push(WriteBackAction { - src: node.clone(), + src: *index, dst: parent.clone(), edge: edge.clone(), }); diff --git a/language/move-prover/bytecode/src/clean_and_optimize.rs b/language/move-prover/bytecode/src/clean_and_optimize.rs index 87f31287b0..f4bc8aecc2 100644 --- a/language/move-prover/bytecode/src/clean_and_optimize.rs +++ b/language/move-prover/bytecode/src/clean_and_optimize.rs @@ -149,7 +149,8 @@ impl<'a> Optimizer<'a> { // Transform code. let mut new_instrs = vec![]; - for (code_offset, instr) in instrs.into_iter().enumerate() { + let mut should_skip = BTreeSet::new(); + for (code_offset, instr) in instrs.iter().enumerate() { use BorrowNode::*; use Bytecode::*; use Operation::*; @@ -162,38 +163,73 @@ impl<'a> Optimizer<'a> { true } }; - if !new_instrs.is_empty() { - // Perform peephole optimization - match (&new_instrs[new_instrs.len() - 1], &instr) { - (Call(_, _, UnpackRef, srcs1, _), Call(_, _, PackRef, srcs2, _)) - if srcs1[0] == srcs2[0] => - { - // skip this redundant unpack/pack pair. - new_instrs.pop(); - continue; + + // Perform peephole optimization + match (new_instrs.last(), instr) { + (None, _) => {} + (Some(Call(_, _, UnpackRef, srcs1, _)), Call(_, _, PackRef, srcs2, _)) + if srcs1[0] == srcs2[0] => + { + // skip this redundant unpack/pack pair. + new_instrs.pop(); + continue; + } + (Some(Call(_, dests, IsParent(..), srcs, _)), Branch(_, _, _, tmp)) + if dests[0] == *tmp + && !is_unwritten(code_offset as CodeOffset, &Reference(srcs[0])) => + { + assert!(matches!(instrs[code_offset + 1], Label(..))); + // skip this obsolete IsParent check when all WriteBacks in this block are redundant + let mut block_cursor = code_offset + 2; + let mut skip_branch = true; + loop { + match &instrs[block_cursor] { + Call(_, _, WriteBack(_, _), srcs, _) => { + if is_unwritten(block_cursor as CodeOffset, &Reference(srcs[0])) { + skip_branch = false; + break; + } + // skip redundant write-backs + should_skip.insert(block_cursor); + } + Call(_, _, TraceLocal(_), _, _) => { + // since the previous write-back is skipped, this trace local is redundant as well + should_skip.insert(block_cursor); + } + _ => { + break; + } + } + block_cursor += 1; } - (Call(_, dests, IsParent(..), srcs, _), Branch(_, _, _, tmp)) - if dests[0] == *tmp - && !is_unwritten(code_offset as CodeOffset, &Reference(srcs[0])) => - { - // skip this obsolete IsParent check + if skip_branch { + // get rid of the label as well + should_skip.insert(code_offset + 1); new_instrs.pop(); continue; } - _ => {} } + (Some(_), _) => {} } - // Remove unnecessary WriteBack - match &instr { + + // Do not include this instruction if it is marked as skipped + if should_skip.contains(&code_offset) { + continue; + } + + // Other cases for skipping the instruction + match instr { + // Remove unnecessary WriteBack Call(_, _, WriteBack(..), srcs, _) if !is_unwritten(code_offset as CodeOffset, &Reference(srcs[0])) => { - // skip this obsolete WriteBack continue; } _ => {} } - new_instrs.push(instr); + + // This instruction should be included + new_instrs.push(instr.clone()); } new_instrs } diff --git a/language/move-prover/bytecode/src/escape_analysis.rs b/language/move-prover/bytecode/src/escape_analysis.rs index e84f98cdba..b5406ddf10 100644 --- a/language/move-prover/bytecode/src/escape_analysis.rs +++ b/language/move-prover/bytecode/src/escape_analysis.rs @@ -295,6 +295,9 @@ impl<'a> TransferFunctions for EscapeAnalysis<'a> { WriteRef | MoveTo(..) => { // these operations do not assign any locals } + Uninit => { + // this operation is just a marker and does not assign any locals + } Destroy => { state.remove(&args[0]); } diff --git a/language/move-prover/bytecode/src/function_data_builder.rs b/language/move-prover/bytecode/src/function_data_builder.rs index f223e91264..01eab763a9 100644 --- a/language/move-prover/bytecode/src/function_data_builder.rs +++ b/language/move-prover/bytecode/src/function_data_builder.rs @@ -210,6 +210,21 @@ impl<'env> FunctionDataBuilder<'env> { (temp, temp_exp) } + /// Similar to `emit_let`, but with the temporary created as identical to the dereference of + /// the mutation (if the `def` argument is a mutable reference). + pub fn emit_let_skip_reference(&mut self, def: Exp) -> (TempIndex, Exp) { + let ty = self + .global_env() + .get_node_type(def.node_id()) + .skip_reference() + .clone(); + let temp = self.new_temp(ty); + let temp_exp = self.mk_temporary(temp); + let definition = self.mk_identical(temp_exp.clone(), def); + self.emit_with(|id| Bytecode::Prop(id, PropKind::Assume, definition)); + (temp, temp_exp) + } + /// Emits a new temporary with a havoced value of given type. pub fn emit_let_havoc(&mut self, ty: Type) -> (TempIndex, Exp) { let havoc_kind = if ty.is_mutable_reference() { diff --git a/language/move-prover/bytecode/src/livevar_analysis.rs b/language/move-prover/bytecode/src/livevar_analysis.rs index 6e399337e2..982aa8e3d7 100644 --- a/language/move-prover/bytecode/src/livevar_analysis.rs +++ b/language/move-prover/bytecode/src/livevar_analysis.rs @@ -216,6 +216,30 @@ impl<'a> LiveVarAnalysis<'a> { let label_to_code_offset = Bytecode::label_offsets(&code); let mut transformed_code = vec![]; let mut new_bytecodes = vec![]; + + // insert marks for uninitialized mutable references + let num_args = self.func_target.get_parameter_count(); + if let Some(info) = annotations.get(&0) { + for index in &info.before { + // only mark the mutable references conditionally defined in function body as uninit + if *index >= num_args + && self + .func_target + .get_local_type(*index) + .is_mutable_reference() + { + transformed_code.push(Bytecode::Call( + self.new_attr_id(), + vec![], + Operation::Uninit, + vec![*index], + None, + )); + } + } + } + + // optimize the function body let mut skip_next = false; for code_offset in 0..code.len() { if skip_next { @@ -252,7 +276,9 @@ impl<'a> LiveVarAnalysis<'a> { // Drop this load/assign as it is not used. } Bytecode::Call(attr_id, dests, oper, srcs, aa) - if code_offset + 1 < code.len() && dests.len() == 1 => + if code_offset + 1 < code.len() + && dests.len() == 1 + && !matches!(oper, Operation::BorrowLoc | Operation::BorrowGlobal(..)) => { // Catch the common case where we have: // @@ -263,6 +289,11 @@ impl<'a> LiveVarAnalysis<'a> { // This is an artifact from transformation from stack to stackless bytecode. // Copy propagation cannot catch this case because it does not have the // livevar information about $t. + // + // With one exception: if the called operation is a BorrowLocal or BorrowGlobal (i.e., an operation + // that creates a root mutable reference), do not optimize it away as we need this local/global root + // reference for our IsParent test. An alternative (i.e., one way to get rid of this exception) is + // to support IsParent test against local and global directly, but that is more complicated. let next_code_offset = code_offset + 1; if let Bytecode::Assign(_, dest, src, _) = &code[next_code_offset] { let annotation_at = &annotations[&(next_code_offset as CodeOffset)]; diff --git a/language/move-prover/bytecode/src/memory_instrumentation.rs b/language/move-prover/bytecode/src/memory_instrumentation.rs index da588e0842..ec9e1d447a 100644 --- a/language/move-prover/bytecode/src/memory_instrumentation.rs +++ b/language/move-prover/bytecode/src/memory_instrumentation.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - borrow_analysis::BorrowAnnotation, + borrow_analysis::{BorrowAnnotation, WriteBackAction}, function_data_builder::FunctionDataBuilder, function_target::FunctionData, function_target_pipeline::{FunctionTargetProcessor, FunctionTargetsHolder}, @@ -20,6 +20,7 @@ use move_model::{ model::{FunctionEnv, StructEnv}, ty::{Type, BOOL_TYPE}, }; +use std::collections::BTreeSet; pub struct MemoryInstrumentationProcessor {} @@ -106,6 +107,39 @@ impl<'a> Instrumenter<'a> { .any(|fe| self.is_pack_ref_ty(&fe.get_type())) } + /// Calculate the differentiating factor for a particular write-back chain (among the tree) + fn get_differentiation_factors(tree: &[Vec], index: usize) -> BTreeSet { + // utility function to first the first different action among two chains + fn index_of_first_different_action( + base: &[WriteBackAction], + another: &[WriteBackAction], + ) -> usize { + for ((i, a1), a2) in base.iter().enumerate().zip(another.iter()) { + if a1 != a2 { + return i; + } + } + unreachable!("Two write-back action chains cannot be exactly the same"); + } + + // derive all the borrow edges that uniquely differentiate this chain + let base = &tree[index]; + let diffs = tree + .iter() + .enumerate() + .filter_map(|(i, chain)| { + if i == index { + None + } else { + Some(index_of_first_different_action(base, chain)) + } + }) + .collect(); + + // return the indices of the actions that differentiate this borrow chain + diffs + } + fn memory_instrumentation(&mut self, code_offset: CodeOffset, bytecode: &Bytecode) { let param_count = self.builder.get_target().get_parameter_count(); @@ -140,6 +174,8 @@ impl<'a> Instrumenter<'a> { // Generate PackRef for nodes which go out of scope, as well as WriteBack. let attr_id = bytecode.get_attr_id(); + self.builder.set_loc_from_attr(attr_id); + for (node, ancestors) in before.dying_nodes(after) { // we only care about references that occurs in the function body let node_idx = match node { @@ -159,73 +195,91 @@ impl<'a> Instrumenter<'a> { // Generate write_back for this reference. let is_conditional = ancestors.len() > 1; - for tree in ancestors { - let parent = match tree.first() { - Some(action) => { - // the src node of the first action must be the node itself - assert!(matches!( - action.src, - BorrowNode::Reference(idx) if idx == node_idx - )); - action - } - None => { - unreachable!( - "The ancestor tree should contain at least one write-back action" - ); - } - }; + for (chain_index, chain) in ancestors.iter().enumerate() { + // sanity check: the src node of the first action must be the node itself + assert_eq!( + chain + .first() + .expect("The write-back chain should contain at action") + .src, + node_idx + ); + + // decide on whether we need IsParent checks and how to instrument the checks + let skip_label_opt = if is_conditional { + let factors = Self::get_differentiation_factors(&ancestors, chain_index); + let mut last_is_parent_temp = None; - // decide on whether we need IsParent checks - self.builder.set_loc_from_attr(attr_id); - let skip_label_opt = match parent.dst { - BorrowNode::Reference(..) if is_conditional => { + for idx in factors { + let action = &chain[idx]; let temp = self.builder.new_temp(BOOL_TYPE.clone()); self.builder.emit_with(|id| { Bytecode::Call( id, vec![temp], - Operation::IsParent(parent.dst.clone(), parent.edge.clone()), - vec![node_idx], + Operation::IsParent(action.dst.clone(), action.edge.clone()), + vec![action.src], None, ) }); - let update_label = self.builder.new_label(); - let skip_label = self.builder.new_label(); - self.builder - .emit_with(|id| Bytecode::Branch(id, update_label, skip_label, temp)); - self.builder - .emit_with(|id| Bytecode::Label(id, update_label)); - Some(skip_label) + + let combined_temp = match last_is_parent_temp { + None => temp, + Some(last_temp) => { + let temp_conjunction = self.builder.new_temp(BOOL_TYPE.clone()); + self.builder.emit_with(|id| { + Bytecode::Call( + id, + vec![temp_conjunction], + Operation::And, + vec![last_temp, temp], + None, + ) + }); + temp_conjunction + } + }; + last_is_parent_temp = Some(combined_temp); } - _ => None, + + let update_label = self.builder.new_label(); + let skip_label = self.builder.new_label(); + self.builder.emit_with(|id| { + Bytecode::Branch( + id, + update_label, + skip_label, + last_is_parent_temp + .expect("There should be at least one IsParent call for a conditional write-back"), + ) + }); + self.builder + .emit_with(|id| Bytecode::Label(id, update_label)); + Some(skip_label) + } else { + None }; // issue a chain of write-back actions - for action in &tree { - // obtain the source of the write-back - let src_idx = match &action.src { - BorrowNode::Reference(idx) => *idx, - _ => unreachable!( - "The source of a write-back action must always be a reference" - ), - }; - + for action in chain { // decide if we need a pack-ref (i.e., data structure invariant checking) if matches!( action.dst, BorrowNode::LocalRoot(..) | BorrowNode::GlobalRoot(..) ) { - // On write-back to a root, "pack" the reference i.e. validate all its - // invariants. - let ty = &self.builder.get_target().get_local_type(src_idx).to_owned(); + // On write-back to a root, "pack" the reference i.e. validate all its invariants. + let ty = &self + .builder + .get_target() + .get_local_type(action.src) + .to_owned(); if self.is_pack_ref_ty(ty) { self.builder.emit_with(|id| { Bytecode::Call( id, vec![], Operation::PackRefDeep, - vec![src_idx], + vec![action.src], None, ) }); @@ -238,7 +292,7 @@ impl<'a> Instrumenter<'a> { id, vec![], Operation::WriteBack(action.dst.clone(), action.edge.clone()), - vec![src_idx], + vec![action.src], None, ) }); diff --git a/language/move-prover/bytecode/src/read_write_set_analysis.rs b/language/move-prover/bytecode/src/read_write_set_analysis.rs index d4a5a83a64..e325665647 100644 --- a/language/move-prover/bytecode/src/read_write_set_analysis.rs +++ b/language/move-prover/bytecode/src/read_write_set_analysis.rs @@ -521,6 +521,9 @@ impl<'a> TransferFunctions for ReadWriteSetAnalysis<'a> { OpaqueCallBegin(_, _, _) | OpaqueCallEnd(_, _, _) => { // skip } + Uninit => { + // do nothing, this marks a reference (args[0]) but the ref is only defined later + } Destroy => state.locals.remove_local(args[0], func_env), Eq | Neq => { // These operations read reference types passed to them. Add Access::Read's for both operands diff --git a/language/move-prover/bytecode/src/spec_instrumentation.rs b/language/move-prover/bytecode/src/spec_instrumentation.rs index 96cb50efdb..04a057e8ec 100644 --- a/language/move-prover/bytecode/src/spec_instrumentation.rs +++ b/language/move-prover/bytecode/src/spec_instrumentation.rs @@ -660,8 +660,13 @@ impl<'a> Instrumenter<'a> { if let Some(c) = &cond { self.emit_traces(&callee_spec, c); } + let temp_msg = self.builder.emit_let(msg).0; - let temp_handle = self.builder.emit_let(handle).0; + // the event handle needs to be let-bound without the reference as we do not want + // to create mutable references via Assume(Identical) as it complicates both + // the live var analysis and the borrow analysis. + let temp_handle = self.builder.emit_let_skip_reference(handle).0; + let mut temp_list = vec![temp_msg, temp_handle]; if let Some(cond) = cond { temp_list.push(self.builder.emit_let(cond).0); diff --git a/language/move-prover/bytecode/src/stackless_bytecode.rs b/language/move-prover/bytecode/src/stackless_bytecode.rs index 421958623a..b3d0824521 100644 --- a/language/move-prover/bytecode/src/stackless_bytecode.rs +++ b/language/move-prover/bytecode/src/stackless_bytecode.rs @@ -128,6 +128,7 @@ pub enum Operation { GetGlobal(ModuleId, StructId, Vec), // Builtins + Uninit, Destroy, ReadRef, WriteRef, @@ -199,6 +200,7 @@ impl Operation { Operation::BorrowGlobal(_, _, _) => true, Operation::GetField(_, _, _, _) => false, Operation::GetGlobal(_, _, _) => true, + Operation::Uninit => false, Operation::Destroy => false, Operation::ReadRef => false, Operation::WriteRef => false, @@ -969,6 +971,9 @@ impl<'env> fmt::Display for OperationDisplay<'env> { } // Builtins + Uninit => { + write!(f, "uninit")?; + } Destroy => { write!(f, "destroy")?; } diff --git a/language/move-prover/bytecode/src/well_formed_instrumentation.rs b/language/move-prover/bytecode/src/well_formed_instrumentation.rs index d8ca7fab98..d72eea808f 100644 --- a/language/move-prover/bytecode/src/well_formed_instrumentation.rs +++ b/language/move-prover/bytecode/src/well_formed_instrumentation.rs @@ -105,8 +105,7 @@ impl FunctionTargetProcessor for WellFormedInstrumentationProcessor { Operation::Global(None), vec![zero_addr], ); - let eq_with_init = - builder.mk_bool_call(Operation::Identical, vec![mem_access, mem_val]); + let eq_with_init = builder.mk_identical(mem_access, mem_val); builder.emit_prop(PropKind::Assume, eq_with_init); } } diff --git a/language/move-prover/bytecode/tests/borrow/basic_test.exp b/language/move-prover/bytecode/tests/borrow/basic_test.exp index b98d5eeef8..6692b3b8dc 100644 --- a/language/move-prover/bytecode/tests/borrow/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow/basic_test.exp @@ -407,7 +407,8 @@ fun TestBorrow::test7($t0|b: bool) { var $t4: u64 var $t5: u64 var $t6: &mut TestBorrow::R - var $t7: u64 + var $t7: &mut TestBorrow::R + var $t8: u64 # live_nodes: LocalRoot($t0) 0: $t4 := 3 # live_nodes: LocalRoot($t0) @@ -425,7 +426,7 @@ fun TestBorrow::test7($t0|b: bool) { # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 6: if ($t0) goto 14 else goto 17 + 6: if ($t0) goto 15 else goto 18 # live_nodes: LocalRoot($t0), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} @@ -437,47 +438,51 @@ fun TestBorrow::test7($t0|b: bool) { # live_nodes: LocalRoot($t0) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 9: $t3 := borrow_local($t2) + 9: $t7 := borrow_local($t2) + # live_nodes: LocalRoot($t0), Reference($t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t2))} + 10: $t3 := $t7 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 10: label L2 + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, Reference($t3))}, Reference($t7) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t2))} + 11: label L2 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 11: $t7 := 0 + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, Reference($t3))}, Reference($t7) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t2))} + 12: $t8 := 0 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 12: TestBorrow::test3($t3, $t7) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, Reference($t3))}, Reference($t7) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t2))} + 13: TestBorrow::test3($t3, $t8) # live_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t6) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 13: return () + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, LocalRoot($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, Reference($t3))}, Reference($t7) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t2))} + 14: return () # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 14: label L3 + 15: label L3 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 15: destroy($t3) + 16: destroy($t3) # live_nodes: LocalRoot($t0), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 16: goto 7 + 17: goto 7 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 17: label L4 + 18: label L4 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 18: destroy($t6) + 19: destroy($t6) # live_nodes: LocalRoot($t0), Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t6))}, Reference($t6) -> {(@, LocalRoot($t1))} - 19: goto 10 + 20: goto 11 } @@ -488,15 +493,18 @@ fun TestBorrow::test8($t0|b: bool, $t1|n: u64, $t2|r_ref: &mut TestBorrow::R) { var $t5|t_ref: &mut TestBorrow::R var $t6: u64 var $t7: u64 - var $t8: u64 - var $t9: bool - var $t10: u64 + var $t8: &mut TestBorrow::R + var $t9: u64 + var $t10: bool var $t11: u64 var $t12: u64 - var $t13: bool - var $t14: u64 - var $t15: u64 - var $t16: u64 + var $t13: u64 + var $t14: bool + var $t15: &mut TestBorrow::R + var $t16: &mut TestBorrow::R + var $t17: u64 + var $t18: u64 + var $t19: u64 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) 0: $t6 := 3 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) @@ -506,143 +514,155 @@ fun TestBorrow::test8($t0|b: bool, $t1|n: u64, $t2|r_ref: &mut TestBorrow::R) { # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) 3: $t4 := pack TestBorrow::R($t7) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - 4: $t5 := borrow_local($t4) + 4: $t8 := borrow_local($t4) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t8) + # borrowed_by: LocalRoot($t4) -> {(@, Reference($t8))} + # borrows_from: Reference($t8) -> {(@, LocalRoot($t4))} + 5: $t5 := $t8 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 5: label L7 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 6: label L7 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 6: $t8 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 7: $t9 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 7: $t9 := <($t8, $t1) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 8: $t10 := <($t9, $t1) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 8: if ($t9) goto 9 else goto 25 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 9: if ($t10) goto 10 else goto 28 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 9: label L0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 10: label L0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 10: destroy($t5) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 11: destroy($t5) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 11: $t10 := 2 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 12: $t11 := 2 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 12: $t11 := /($t1, $t10) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 13: $t12 := /($t1, $t11) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 13: $t12 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 14: $t13 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 14: $t13 := ==($t11, $t12) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 15: $t14 := ==($t12, $t13) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 15: if ($t13) goto 16 else goto 19 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 16: if ($t14) goto 17 else goto 21 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 16: label L3 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 17: label L3 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 17: $t5 := borrow_local($t3) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 18: $t15 := borrow_local($t3) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t15) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 19: $t5 := $t15 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 18: goto 21 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 20: goto 24 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 19: label L5 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 21: label L5 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 20: $t5 := borrow_local($t4) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 22: $t16 := borrow_local($t4) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t16) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 23: $t5 := $t16 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 21: label L6 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 24: label L6 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 22: $t14 := 1 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 25: $t17 := 1 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 23: $t1 := -($t1, $t14) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 26: $t1 := -($t1, $t17) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 24: goto 5 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 27: goto 6 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 25: label L2 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 28: label L2 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 26: if ($t0) goto 27 else goto 32 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 29: if ($t0) goto 30 else goto 35 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 27: label L8 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 30: label L8 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 28: destroy($t5) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 31: destroy($t5) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 29: $t15 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 32: $t18 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 30: TestBorrow::test3($t2, $t15) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 33: TestBorrow::test3($t2, $t18) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 31: goto 36 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 34: goto 39 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 32: label L10 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 35: label L10 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 33: destroy($t2) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 36: destroy($t2) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 34: $t16 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 37: $t19 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 35: TestBorrow::test3($t5, $t16) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 38: TestBorrow::test3($t5, $t19) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 36: label L11 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 39: label L11 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 37: trace_local[r_ref]($t2) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 40: trace_local[r_ref]($t2) # live_nodes: LocalRoot($t0), LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 38: return () + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t15))}, LocalRoot($t4) -> {(@, Reference($t8)), (@, Reference($t16))}, Reference($t8) -> {(@, Reference($t5))}, Reference($t15) -> {(@, Reference($t5))}, Reference($t16) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t8)), (@, Reference($t15)), (@, Reference($t16))}, Reference($t8) -> {(@, LocalRoot($t4))}, Reference($t15) -> {(@, LocalRoot($t3))}, Reference($t16) -> {(@, LocalRoot($t4))} + 41: return () } diff --git a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp index f6c8c85f2c..bd081df2da 100644 --- a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp @@ -627,7 +627,8 @@ fun TestBorrow::test7($t0|b: bool) { var $t6: u64 var $t7: u64 var $t8: &mut TestBorrow::R - var $t9: u64 + var $t9: &mut TestBorrow::R + var $t10: u64 # live_nodes: LocalRoot($t0) 0: $t4 := 3 # live_nodes: LocalRoot($t0) @@ -649,7 +650,7 @@ fun TestBorrow::test7($t0|b: bool) { # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 8: if ($t0) goto 16 else goto 19 + 8: if ($t0) goto 17 else goto 20 # live_nodes: LocalRoot($t0), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} @@ -661,47 +662,51 @@ fun TestBorrow::test7($t0|b: bool) { # live_nodes: LocalRoot($t0) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 11: $t3 := borrow_local($t2) + 11: $t9 := borrow_local($t2) + # live_nodes: LocalRoot($t0), Reference($t9) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t9))}, Reference($t8) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t2))} + 12: $t3 := $t9 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 12: label L2 + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t9))}, Reference($t8) -> {(@, Reference($t3))}, Reference($t9) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8)), (@, Reference($t9))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t2))} + 13: label L2 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 13: $t9 := 0 + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t9))}, Reference($t8) -> {(@, Reference($t3))}, Reference($t9) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8)), (@, Reference($t9))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t2))} + 14: $t10 := 0 # live_nodes: LocalRoot($t0), Reference($t3) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 14: TestBorrow::test3($t3, $t9) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t9))}, Reference($t8) -> {(@, Reference($t3))}, Reference($t9) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8)), (@, Reference($t9))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t2))} + 15: TestBorrow::test3($t3, $t10) # live_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t3))}, Reference($t8) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t2)), (@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 15: return () + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, LocalRoot($t2) -> {(@, Reference($t9))}, Reference($t8) -> {(@, Reference($t3))}, Reference($t9) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, Reference($t8)), (@, Reference($t9))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t2))} + 16: return () # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 16: label L3 + 17: label L3 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 17: destroy($t3) + 18: destroy($t3) # live_nodes: LocalRoot($t0), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 18: goto 9 + 19: goto 9 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 19: label L4 + 20: label L4 # live_nodes: LocalRoot($t0), Reference($t3), Reference($t8) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 20: destroy($t8) + 21: destroy($t8) # live_nodes: LocalRoot($t0), Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t8))}, Reference($t8) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, Reference($t8))}, Reference($t8) -> {(@, LocalRoot($t1))} - 21: goto 12 + 22: goto 13 } @@ -714,15 +719,18 @@ fun TestBorrow::test8($t0|b: bool, $t1|n: u64, $t2|r_ref: &mut TestBorrow::R) { var $t7: u64 var $t8: u64 var $t9: u64 - var $t10: u64 - var $t11: bool - var $t12: u64 + var $t10: &mut TestBorrow::R + var $t11: u64 + var $t12: bool var $t13: u64 var $t14: u64 - var $t15: bool - var $t16: u64 - var $t17: u64 - var $t18: u64 + var $t15: u64 + var $t16: bool + var $t17: &mut TestBorrow::R + var $t18: &mut TestBorrow::R + var $t19: u64 + var $t20: u64 + var $t21: u64 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) 0: $t6 := 3 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) @@ -736,143 +744,155 @@ fun TestBorrow::test8($t0|b: bool, $t1|n: u64, $t2|r_ref: &mut TestBorrow::R) { # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) 5: $t4 := pack TestBorrow::R($t8, $t9) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - 6: $t5 := borrow_local($t4) + 6: $t10 := borrow_local($t4) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t10) + # borrowed_by: LocalRoot($t4) -> {(@, Reference($t10))} + # borrows_from: Reference($t10) -> {(@, LocalRoot($t4))} + 7: $t5 := $t10 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 7: label L7 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 8: label L7 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 8: $t10 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 9: $t11 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 9: $t11 := <($t10, $t1) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 10: $t12 := <($t11, $t1) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 10: if ($t11) goto 11 else goto 27 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 11: if ($t12) goto 12 else goto 30 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 11: label L0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 12: label L0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 12: destroy($t5) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 13: destroy($t5) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 13: $t12 := 2 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 14: $t13 := 2 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 14: $t13 := /($t1, $t12) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 15: $t14 := /($t1, $t13) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 15: $t14 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 16: $t15 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 16: $t15 := ==($t13, $t14) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 17: $t16 := ==($t14, $t15) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 17: if ($t15) goto 18 else goto 21 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 18: if ($t16) goto 19 else goto 23 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 18: label L3 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 19: label L3 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 19: $t5 := borrow_local($t3) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 20: $t17 := borrow_local($t3) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t17) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 21: $t5 := $t17 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 20: goto 23 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 22: goto 26 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 21: label L5 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 23: label L5 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 22: $t5 := borrow_local($t4) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 24: $t18 := borrow_local($t4) + # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t18) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 25: $t5 := $t18 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 23: label L6 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 26: label L6 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 24: $t16 := 1 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 27: $t19 := 1 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 25: $t1 := -($t1, $t16) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 28: $t1 := -($t1, $t19) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 26: goto 7 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 29: goto 8 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 27: label L2 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 30: label L2 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 28: if ($t0) goto 29 else goto 34 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 31: if ($t0) goto 32 else goto 37 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 29: label L8 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 32: label L8 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 30: destroy($t5) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 33: destroy($t5) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 31: $t17 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 34: $t20 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 32: TestBorrow::test3($t2, $t17) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 35: TestBorrow::test3($t2, $t20) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 33: goto 38 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 36: goto 41 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 34: label L10 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 37: label L10 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 35: destroy($t2) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 38: destroy($t2) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 36: $t18 := 0 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 39: $t21 := 0 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2), Reference($t5) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 37: TestBorrow::test3($t5, $t18) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 40: TestBorrow::test3($t5, $t21) # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 38: label L11 + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 41: label L11 # live_nodes: LocalRoot($t0), LocalRoot($t1), Reference($t2) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 39: trace_local[r_ref]($t2) + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 42: trace_local[r_ref]($t2) # live_nodes: LocalRoot($t0), LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t5))}, LocalRoot($t4) -> {(@, Reference($t5))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t3)), (@, LocalRoot($t4))} - 40: return () + # borrowed_by: LocalRoot($t3) -> {(@, Reference($t17))}, LocalRoot($t4) -> {(@, Reference($t10)), (@, Reference($t18))}, Reference($t10) -> {(@, Reference($t5))}, Reference($t17) -> {(@, Reference($t5))}, Reference($t18) -> {(@, Reference($t5))} + # borrows_from: Reference($t5) -> {(@, Reference($t10)), (@, Reference($t17)), (@, Reference($t18))}, Reference($t10) -> {(@, LocalRoot($t4))}, Reference($t17) -> {(@, LocalRoot($t3))}, Reference($t18) -> {(@, LocalRoot($t4))} + 43: return () } diff --git a/language/move-prover/bytecode/tests/memory_instr/basic_test.exp b/language/move-prover/bytecode/tests/memory_instr/basic_test.exp index 10f040b31e..a264314ac3 100644 --- a/language/move-prover/bytecode/tests/memory_instr/basic_test.exp +++ b/language/move-prover/bytecode/tests/memory_instr/basic_test.exp @@ -357,40 +357,48 @@ fun TestPackref::test7($t0|b: bool) { var $t4: u64 var $t5: u64 var $t6: &mut TestPackref::R - var $t7: u64 - var $t8: bool + var $t7: &mut TestPackref::R + var $t8: u64 + var $t9: bool + var $t10: bool 0: $t4 := 3 1: $t1 := pack TestPackref::R($t4) 2: $t5 := 4 3: $t2 := pack TestPackref::R($t5) 4: $t6 := borrow_local($t1) 5: $t3 := $t6 - 6: if ($t0) goto 25 else goto 29 + 6: if ($t0) goto 31 else goto 35 7: label L0 8: write_back[LocalRoot($t1)@]($t6) 9: trace_local[r1]($t1) 10: destroy($t6) - 11: $t3 := borrow_local($t2) - 12: label L2 - 13: $t7 := 0 - 14: TestPackref::test3($t3, $t7) - 15: write_back[LocalRoot($t2)@]($t3) - 16: trace_local[r2]($t2) - 17: $t8 := is_parent[Reference($t6)@]($t3) - 18: if ($t8) goto 19 else goto 23 - 19: label L5 - 20: write_back[Reference($t6)@]($t3) - 21: write_back[LocalRoot($t1)@]($t6) - 22: trace_local[r1]($t1) - 23: label L6 - 24: return () - 25: label L3 - 26: write_back[Reference($t6)@]($t3) - 27: destroy($t3) - 28: goto 7 - 29: label L4 - 30: destroy($t6) - 31: goto 12 + 11: $t7 := borrow_local($t2) + 12: $t3 := $t7 + 13: label L2 + 14: $t8 := 0 + 15: TestPackref::test3($t3, $t8) + 16: $t9 := is_parent[Reference($t6)@]($t3) + 17: if ($t9) goto 18 else goto 22 + 18: label L5 + 19: write_back[Reference($t6)@]($t3) + 20: write_back[LocalRoot($t1)@]($t6) + 21: trace_local[r1]($t1) + 22: label L6 + 23: $t10 := is_parent[Reference($t7)@]($t3) + 24: if ($t10) goto 25 else goto 29 + 25: label L7 + 26: write_back[Reference($t7)@]($t3) + 27: write_back[LocalRoot($t2)@]($t7) + 28: trace_local[r2]($t2) + 29: label L8 + 30: return () + 31: label L3 + 32: write_back[Reference($t6)@]($t3) + 33: destroy($t3) + 34: goto 7 + 35: label L4 + 36: destroy($t6) + 37: goto 13 } @@ -401,64 +409,130 @@ fun TestPackref::test8($t0|b: bool, $t1|n: u64, $t2|r_ref: &mut TestPackref::R) var $t5|t_ref: &mut TestPackref::R var $t6: u64 var $t7: u64 - var $t8: u64 - var $t9: bool - var $t10: u64 + var $t8: &mut TestPackref::R + var $t9: u64 + var $t10: bool var $t11: u64 var $t12: u64 - var $t13: bool - var $t14: u64 - var $t15: u64 - var $t16: u64 + var $t13: u64 + var $t14: bool + var $t15: &mut TestPackref::R + var $t16: &mut TestPackref::R + var $t17: u64 + var $t18: u64 + var $t19: u64 + var $t20: bool + var $t21: bool + var $t22: bool + var $t23: bool + var $t24: bool + var $t25: bool + var $t26: bool + var $t27: bool + var $t28: bool 0: $t6 := 3 1: $t3 := pack TestPackref::R($t6) 2: $t7 := 4 3: $t4 := pack TestPackref::R($t7) - 4: $t5 := borrow_local($t4) - 5: label L7 - 6: $t8 := 0 - 7: $t9 := <($t8, $t1) - 8: if ($t9) goto 9 else goto 29 - 9: label L0 - 10: write_back[LocalRoot($t3)@]($t5) - 11: trace_local[r1]($t3) - 12: write_back[LocalRoot($t4)@]($t5) - 13: trace_local[r2]($t4) - 14: destroy($t5) - 15: $t10 := 2 - 16: $t11 := /($t1, $t10) - 17: $t12 := 0 - 18: $t13 := ==($t11, $t12) - 19: if ($t13) goto 20 else goto 23 - 20: label L3 - 21: $t5 := borrow_local($t3) - 22: goto 25 - 23: label L5 - 24: $t5 := borrow_local($t4) - 25: label L6 - 26: $t14 := 1 - 27: $t1 := -($t1, $t14) - 28: goto 5 - 29: label L2 - 30: if ($t0) goto 31 else goto 40 - 31: label L8 - 32: write_back[LocalRoot($t3)@]($t5) - 33: trace_local[r1]($t3) - 34: write_back[LocalRoot($t4)@]($t5) - 35: trace_local[r2]($t4) - 36: destroy($t5) - 37: $t15 := 0 - 38: TestPackref::test3($t2, $t15) - 39: goto 48 - 40: label L10 - 41: destroy($t2) - 42: $t16 := 0 - 43: TestPackref::test3($t5, $t16) - 44: write_back[LocalRoot($t3)@]($t5) - 45: trace_local[r1]($t3) - 46: write_back[LocalRoot($t4)@]($t5) - 47: trace_local[r2]($t4) - 48: label L11 - 49: trace_local[r_ref]($t2) - 50: return () + 4: $t8 := borrow_local($t4) + 5: $t5 := $t8 + 6: label L7 + 7: $t9 := 0 + 8: $t10 := <($t9, $t1) + 9: if ($t10) goto 10 else goto 49 + 10: label L0 + 11: $t20 := is_parent[Reference($t8)@]($t5) + 12: if ($t20) goto 13 else goto 17 + 13: label L12 + 14: write_back[Reference($t8)@]($t5) + 15: write_back[LocalRoot($t4)@]($t8) + 16: trace_local[r2]($t4) + 17: label L13 + 18: $t21 := is_parent[Reference($t15)@]($t5) + 19: if ($t21) goto 20 else goto 24 + 20: label L14 + 21: write_back[Reference($t15)@]($t5) + 22: write_back[LocalRoot($t3)@]($t15) + 23: trace_local[r1]($t3) + 24: label L15 + 25: $t22 := is_parent[Reference($t16)@]($t5) + 26: if ($t22) goto 27 else goto 31 + 27: label L16 + 28: write_back[Reference($t16)@]($t5) + 29: write_back[LocalRoot($t4)@]($t16) + 30: trace_local[r2]($t4) + 31: label L17 + 32: destroy($t5) + 33: $t11 := 2 + 34: $t12 := /($t1, $t11) + 35: $t13 := 0 + 36: $t14 := ==($t12, $t13) + 37: if ($t14) goto 38 else goto 42 + 38: label L3 + 39: $t15 := borrow_local($t3) + 40: $t5 := $t15 + 41: goto 45 + 42: label L5 + 43: $t16 := borrow_local($t4) + 44: $t5 := $t16 + 45: label L6 + 46: $t17 := 1 + 47: $t1 := -($t1, $t17) + 48: goto 6 + 49: label L2 + 50: if ($t0) goto 51 else goto 77 + 51: label L8 + 52: $t23 := is_parent[Reference($t8)@]($t5) + 53: if ($t23) goto 54 else goto 58 + 54: label L18 + 55: write_back[Reference($t8)@]($t5) + 56: write_back[LocalRoot($t4)@]($t8) + 57: trace_local[r2]($t4) + 58: label L19 + 59: $t24 := is_parent[Reference($t15)@]($t5) + 60: if ($t24) goto 61 else goto 65 + 61: label L20 + 62: write_back[Reference($t15)@]($t5) + 63: write_back[LocalRoot($t3)@]($t15) + 64: trace_local[r1]($t3) + 65: label L21 + 66: $t25 := is_parent[Reference($t16)@]($t5) + 67: if ($t25) goto 68 else goto 72 + 68: label L22 + 69: write_back[Reference($t16)@]($t5) + 70: write_back[LocalRoot($t4)@]($t16) + 71: trace_local[r2]($t4) + 72: label L23 + 73: destroy($t5) + 74: $t18 := 0 + 75: TestPackref::test3($t2, $t18) + 76: goto 102 + 77: label L10 + 78: destroy($t2) + 79: $t19 := 0 + 80: TestPackref::test3($t5, $t19) + 81: $t26 := is_parent[Reference($t8)@]($t5) + 82: if ($t26) goto 83 else goto 87 + 83: label L24 + 84: write_back[Reference($t8)@]($t5) + 85: write_back[LocalRoot($t4)@]($t8) + 86: trace_local[r2]($t4) + 87: label L25 + 88: $t27 := is_parent[Reference($t15)@]($t5) + 89: if ($t27) goto 90 else goto 94 + 90: label L26 + 91: write_back[Reference($t15)@]($t5) + 92: write_back[LocalRoot($t3)@]($t15) + 93: trace_local[r1]($t3) + 94: label L27 + 95: $t28 := is_parent[Reference($t16)@]($t5) + 96: if ($t28) goto 97 else goto 101 + 97: label L28 + 98: write_back[Reference($t16)@]($t5) + 99: write_back[LocalRoot($t4)@]($t16) +100: trace_local[r2]($t4) +101: label L29 +102: label L11 +103: trace_local[r_ref]($t2) +104: return () } diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.exp index 95cffca6eb..30578ec20c 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.exp +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.exp @@ -1,3 +1,4 @@ Running Move unit tests -[ PASS ] 0x2::A::if_else -Test result: OK. Total tests: 1; passed: 1; failed: 0 +[ PASS ] 0x2::A::if_else_1 +[ PASS ] 0x2::A::if_else_2 +Test result: OK. Total tests: 2; passed: 2; failed: 0 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.move index d08dc5e541..7a790d828b 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/if_else.move @@ -1,10 +1,20 @@ module 0x2::A { #[test] - public fun if_else(): (u64, u64) { + public fun if_else_1(): (u64, u64) { let a = 1; let b = 2; let r = if (a > b) { &mut a } else { &mut b }; *r = 3; (a, b) } + + #[test] + public fun if_else_2(): (u64, u64) { + let a = 2; + let b = 1; + let r = if (a > b) { &mut a } else { &mut b }; + *r = 3; + (a, b) + } + } diff --git a/language/move-prover/interpreter/src/concrete/local_state.rs b/language/move-prover/interpreter/src/concrete/local_state.rs index 3bbbdc5330..b2ef58a077 100644 --- a/language/move-prover/interpreter/src/concrete/local_state.rs +++ b/language/move-prover/interpreter/src/concrete/local_state.rs @@ -5,7 +5,7 @@ //! This file implements the information needed in the local interpretation context, i.e., the //! context created and updated when interpreting a single function. -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use move_binary_format::errors::{Location, PartialVMError, VMError}; use move_core_types::vm_status::StatusCode; @@ -71,6 +71,8 @@ pub struct LocalState { destroyed_args: BTreeMap, /// whether specification checking needs to be skipped skip_specs: bool, + /// local mutable references that are explicitly marked as uninit + uninit_mut_refs: BTreeSet, } impl LocalState { @@ -82,6 +84,7 @@ impl LocalState { termination: TerminationStatus::None, destroyed_args: BTreeMap::new(), skip_specs, + uninit_mut_refs: BTreeSet::new(), } } @@ -128,6 +131,18 @@ impl LocalState { self.destroyed_args.remove(&index).unwrap() } + /// Mark a mutable reference is uninitialized explicitly + pub fn mark_uninit(&mut self, index: TempIndex) { + let inserted = self.uninit_mut_refs.insert(index); + if cfg!(debug_assertions) { + assert!(inserted); + } + } + /// Unset the mark that the mutable reference is uninitialized, return True if unset + pub fn unset_uninit(&mut self, index: TempIndex) -> bool { + self.uninit_mut_refs.remove(&index) + } + /// Get the current PC location (i.e., which bytecode to be executed) pub fn get_pc(&self) -> CodeOffset { self.pc diff --git a/language/move-prover/interpreter/src/concrete/player.rs b/language/move-prover/interpreter/src/concrete/player.rs index d03dbec6ef..10fe4d9afc 100644 --- a/language/move-prover/interpreter/src/concrete/player.rs +++ b/language/move-prover/interpreter/src/concrete/player.rs @@ -386,12 +386,25 @@ impl<'env> FunctionContext<'env> { kind: &AssignKind, local_state: &mut LocalState, ) { - let from_val = match kind { - AssignKind::Move => local_state.del_value(src), - // TODO (mengxu): what exactly is the semantic of Store here? Why not just use Copy? - AssignKind::Copy | AssignKind::Store => local_state.get_value(src), + let into_val = match kind { + AssignKind::Move => { + let from_val = local_state.del_value(src); + from_val.assign_cast(local_state.get_type(dst).clone()) + } + AssignKind::Copy => { + let from_val = local_state.get_value(src); + from_val.assign_cast(local_state.get_type(dst).clone()) + } + AssignKind::Store => { + let from_val = local_state.get_value(src); + let into_ty = local_state.get_type(dst).clone(); + if from_val.get_ty().is_ref(Some(true)) { + from_val.borrow_direct(into_ty, src) + } else { + from_val.assign_cast(into_ty) + } + } }; - let into_val = from_val.assign_cast(local_state.get_type(dst).clone()); local_state.put_value_override(dst, into_val); } @@ -439,6 +452,24 @@ impl<'env> FunctionContext<'env> { // operations that does not need to have the argument in storage match op { // built-ins + Operation::Uninit => { + if cfg!(debug_assertions) { + assert_eq!(srcs.len(), 1); + } + self.handle_uninit(srcs[0], local_state); + return Ok(()); + } + Operation::Destroy => { + if cfg!(debug_assertions) { + assert_eq!(srcs.len(), 1); + } + self.handle_destroy(srcs[0], local_state); + return Ok(()); + } + Operation::Stop => { + // we should never see the Stop operation in interpreter mode + unreachable!() + } Operation::Havoc(kind) => { if cfg!(debug_assertions) { assert_eq!(srcs.len(), 1); @@ -747,18 +778,6 @@ impl<'env> FunctionContext<'env> { let object = self.handle_freeze_ref(typed_args.remove(0)); Ok(vec![object]) } - // built-in - Operation::Destroy => { - if cfg!(debug_assertions) { - assert_eq!(typed_args.len(), 1); - } - self.handle_destroy(srcs[0], local_state); - Ok(vec![]) - } - Operation::Stop => { - // we should never see the Stop operation in interpreter mode - unreachable!() - } // cast Operation::CastU8 | Operation::CastU64 | Operation::CastU128 => { if cfg!(debug_assertions) { @@ -850,7 +869,10 @@ impl<'env> FunctionContext<'env> { // event (TODO: not supported yet) Operation::EmitEvent | Operation::EventStoreDiverge => Ok(vec![]), // already handled - Operation::Havoc(..) + Operation::Stop + | Operation::Uninit + | Operation::Destroy + | Operation::Havoc(..) | Operation::TraceLocal(..) | Operation::TraceReturn(..) | Operation::TraceAbort @@ -1167,6 +1189,7 @@ impl<'env> FunctionContext<'env> { let (_, _, ptr) = op_val.decompose(); let is_parent = match ptr { + Pointer::RefDirect(idx) => idx == parent_idx, Pointer::RefField(idx, _) => idx == parent_idx, Pointer::RefElement(idx, _) => idx == parent_idx, Pointer::ArgRef(idx, _) => idx == parent_idx, @@ -1234,9 +1257,10 @@ impl<'env> FunctionContext<'env> { } match op_val.get_ptr() { Pointer::Local(root_idx) => { - if *root_idx == local_root { - local_state.put_value_override(local_root, op_val.read_ref()); + if cfg!(debug_assertions) { + assert_eq!(*root_idx, local_root); } + local_state.put_value_override(local_root, op_val.read_ref()); } _ => unreachable!(), } @@ -1253,10 +1277,18 @@ impl<'env> FunctionContext<'env> { let new_ty = op_val.get_ty(); assert!(new_ty.is_ref(Some(true))); assert_eq!(new_ty, old_val.get_ty()); + } - // check pointer validity - match op_val.get_ptr() { - Pointer::RetRef(trace) => { + let new_val = match op_val.get_ptr() { + Pointer::RefDirect(parent_idx) => { + if cfg!(debug_assertions) { + assert_eq!(*parent_idx, local_ref); + } + old_val.update_ref_direct(op_val) + } + Pointer::RetRef(trace) => { + // check pointer validity + if cfg!(debug_assertions) { assert_eq!(trace.len(), 1); match trace.get(0).unwrap() { Pointer::ArgRef(ref_idx, original_ptr) => { @@ -1266,10 +1298,10 @@ impl<'env> FunctionContext<'env> { _ => unreachable!(), } } - _ => unreachable!(), + op_val.unbox_from_mut_ref_ret() } - } - let new_val = op_val.unbox_from_mut_ref_ret(); + _ => unreachable!(), + }; local_state.put_value(local_ref, new_val); } @@ -1471,10 +1503,23 @@ impl<'env> FunctionContext<'env> { ref_val.freeze_ref() } + fn handle_uninit(&self, local_idx: TempIndex, local_state: &mut LocalState) { + if cfg!(debug_assertions) { + assert!(!local_state.has_value(local_idx)); + } + local_state.mark_uninit(local_idx); + } + fn handle_destroy(&self, local_idx: TempIndex, local_state: &mut LocalState) { - let val = local_state.del_value(local_idx); - if local_idx < self.target.get_parameter_count() { - local_state.save_destroyed_arg(local_idx, val); + if local_state.unset_uninit(local_idx) { + if cfg!(debug_assertions) { + assert!(!local_state.has_value(local_idx)); + } + } else { + let val = local_state.del_value(local_idx); + if local_idx < self.target.get_parameter_count() { + local_state.save_destroyed_arg(local_idx, val); + } } } diff --git a/language/move-prover/interpreter/src/concrete/value.rs b/language/move-prover/interpreter/src/concrete/value.rs index 09135291fd..5d681336d1 100644 --- a/language/move-prover/interpreter/src/concrete/value.rs +++ b/language/move-prover/interpreter/src/concrete/value.rs @@ -135,6 +135,7 @@ pub enum Pointer { None, Global(AccountAddress), Local(TempIndex), + RefDirect(TempIndex), RefField(TempIndex, usize), RefElement(TempIndex, usize), ArgRef(TempIndex, Box), @@ -493,6 +494,18 @@ impl TypedValue { } } + /// Create a reference that is a direct borrow of another reference value + pub fn borrow_direct(self, ty: Type, local_idx: TempIndex) -> TypedValue { + if cfg!(debug_assertions) { + assert!(ty.is_compatible_for_assign(&self.ty)); + } + TypedValue { + ty, + val: self.val, + ptr: Pointer::RefDirect(local_idx), + } + } + /// Create a reference to the base value pub fn borrow_local(self, is_mut: bool, local_idx: TempIndex) -> TypedValue { TypedValue { @@ -572,6 +585,9 @@ impl TypedValue { ) { match cur { Pointer::ArgRef(_, _) => trace.push(cur.clone()), + Pointer::RefDirect(idx) => { + follow_return_pointers_recursive(ptrs.get(idx).unwrap(), ptrs, trace); + } Pointer::RefField(idx, _) | Pointer::RefElement(idx, _) => { trace.push(cur.clone()); follow_return_pointers_recursive(ptrs.get(idx).unwrap(), ptrs, trace); @@ -623,6 +639,21 @@ impl TypedValue { } } + /// update the reference directly + pub fn update_ref_direct(self, ref_val: TypedValue) -> TypedValue { + let (old_ty, _, old_ptr) = self.decompose(); + let (new_ty, new_val, _) = ref_val.decompose(); + if cfg!(debug_assertions) { + assert!(old_ty.is_ref(Some(true))); + assert_eq!(old_ty, new_ty); + } + TypedValue { + ty: old_ty, + val: new_val, + ptr: old_ptr, + } + } + /// Retrieve an element from a vector at the given index. Return None of index out-of-bounds. pub fn get_vector_element(self, elem_num: usize) -> Option { let elem_ty = self.ty.into_vector_elem(); diff --git a/language/move-prover/tests/sources/functional/conditional_write_back.move b/language/move-prover/tests/sources/functional/conditional_write_back.move index fc3f958443..77e6b7a8e8 100644 --- a/language/move-prover/tests/sources/functional/conditional_write_back.move +++ b/language/move-prover/tests/sources/functional/conditional_write_back.move @@ -96,4 +96,35 @@ module 0x42::Test { aborts_if !cond && !exists>(a); ensures if (cond) global>(a).x == 0 else global>(a).x == 0; } + + public fun diff_local_simple(cond: bool) { + let v1 = 0; + let v2 = 0; + + let r = if (cond) { &mut v1 } else { &mut v2 }; + *r = 1; + + spec { + assert (cond) ==> (v1 == 1 && v2 == 0); + assert (!cond) ==> (v1 == 0 && v2 == 1); + } + } + + public fun diff_local_global_mix_simple(cond: bool) acquires T { + let t = T { x : 0 }; + let r = if (cond) { borrow_global_mut(@0x1) } else { &mut t }; + r.x = 1; + + spec { + assert (cond) ==> t.x == 0; + assert (!cond) ==> t.x == 1; + }; + + let T { x : _ } = t; + } + spec diff_local_global_mix_simple { + aborts_if cond && !exists(@0x1); + ensures (cond) ==> global(@0x1).x == 1; + ensures (!cond) ==> global(@0x1).x == old(global(@0x1).x); + } } diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp index 35773607e1..c51e6bbfaa 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.cvc5_exp @@ -6,6 +6,8 @@ error: unknown assertion failed │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 = a = = b = = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 @@ -59,6 +61,8 @@ error: induction case of the loop invariant does not hold │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 = a = = b = = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp index bdf5525e71..b22828139c 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp @@ -6,6 +6,8 @@ error: unknown assertion failed │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 = a = = b = = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 @@ -43,13 +45,10 @@ error: unknown assertion failed = y = = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = b = + = a = + = a = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 @@ -62,6 +61,8 @@ error: induction case of the loop invariant does not hold │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:56: nested_loop2 = a = = b = = at tests/sources/functional/loops_with_memory_ops.move:57: nested_loop2 @@ -103,8 +104,7 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at :1 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = a = = at :1 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 diff --git a/language/move-prover/tests/sources/functional/macro_verification.exp b/language/move-prover/tests/sources/functional/macro_verification.exp index 9ed2446485..2728b4190a 100644 --- a/language/move-prover/tests/sources/functional/macro_verification.exp +++ b/language/move-prover/tests/sources/functional/macro_verification.exp @@ -10,6 +10,8 @@ error: post-condition does not hold = v = = Execution Trace: = at tests/sources/functional/macro_verification.move:15: foreach + = at :1 + = at tests/sources/functional/macro_verification.move:15: foreach = v = = at tests/sources/functional/macro_verification.move:16: foreach = i = diff --git a/language/move-prover/tests/sources/functional/mut_ref.exp b/language/move-prover/tests/sources/functional/mut_ref.exp index 4c5c61e7d7..7b8f95897e 100644 --- a/language/move-prover/tests/sources/functional/mut_ref.exp +++ b/language/move-prover/tests/sources/functional/mut_ref.exp @@ -36,8 +36,6 @@ error: data invariant does not hold = at tests/sources/functional/mut_ref.move:91: return_ref_different_path_vec2 = result = = x = - = x = - = x = = at tests/sources/functional/mut_ref.move:92: return_ref_different_path_vec2 = r = = at tests/sources/functional/mut_ref.move:122: call_return_ref_different_path_vec2_incorrect From aba7070cf6f553f85ac6874da1e3630bbc32e44a Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Fri, 29 Jul 2022 23:59:42 -0400 Subject: [PATCH 018/169] [move-prover] remove the destroy instruction for imm borrow removal (#323) The `destroy($t1)` bytecode is not removed in the immutable borrow pass, which it should be, otherwise we will observe an `destroy($t1)` where `$t1` is not a reference type. This does not cause any issue with the symbolic reasoning as `destroy` is essentially translated into a no-op. Instead, it is caught by the concrete executor. --- .../bytecode/src/eliminate_imm_refs.rs | 3 + .../tests/eliminate_imm_refs/basic_test.exp | 41 ++++++++++++++ .../tests/eliminate_imm_refs/basic_test.move | 7 +++ .../bytecode/tests/livevar/basic_test.exp | 56 +++++++++---------- .../tests/concrete_check/destroy.exp | 3 +- .../tests/concrete_check/destroy.move | 3 +- 6 files changed, 80 insertions(+), 33 deletions(-) diff --git a/language/move-prover/bytecode/src/eliminate_imm_refs.rs b/language/move-prover/bytecode/src/eliminate_imm_refs.rs index 93a2e97e13..baf42b3fca 100644 --- a/language/move-prover/bytecode/src/eliminate_imm_refs.rs +++ b/language/move-prover/bytecode/src/eliminate_imm_refs.rs @@ -105,6 +105,9 @@ impl<'a> EliminateImmRefs<'a> { aa, )); } + Destroy if self.is_imm_ref(srcs[0]) => { + // skip the destroy on an immutable ref + } _ => self.builder.emit(Call(attr_id, dests, op, srcs, aa)), }, _ => self.builder.emit(bytecode), diff --git a/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.exp b/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.exp index f208761943..e7ef8ac095 100644 --- a/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.exp +++ b/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.exp @@ -90,6 +90,27 @@ fun TestEliminateImmRefs::test4(): u64 { 7: return $t6 } + +[variant baseline] +fun TestEliminateImmRefs::test5(): TestEliminateImmRefs::R { + var $t0|p: &TestEliminateImmRefs::R + var $t1|r: TestEliminateImmRefs::R + var $t2: u64 + var $t3: TestEliminateImmRefs::R + var $t4: &TestEliminateImmRefs::R + var $t5: &TestEliminateImmRefs::R + var $t6: TestEliminateImmRefs::R + 0: $t2 := 3 + 1: $t3 := pack TestEliminateImmRefs::R($t2) + 2: $t1 := $t3 + 3: $t4 := borrow_local($t1) + 4: $t0 := $t4 + 5: $t5 := move($t0) + 6: destroy($t5) + 7: $t6 := move($t1) + 8: return $t6 +} + ============ after pipeline `eliminate_imm_refs` ================ [variant baseline] @@ -181,3 +202,23 @@ fun TestEliminateImmRefs::test4(): u64 { 6: $t6 := TestEliminateImmRefs::test3($t5) 7: return $t6 } + + +[variant baseline] +fun TestEliminateImmRefs::test5(): TestEliminateImmRefs::R { + var $t0|p: TestEliminateImmRefs::R + var $t1|r: TestEliminateImmRefs::R + var $t2: u64 + var $t3: TestEliminateImmRefs::R + var $t4: TestEliminateImmRefs::R + var $t5: TestEliminateImmRefs::R + var $t6: TestEliminateImmRefs::R + 0: $t2 := 3 + 1: $t3 := pack TestEliminateImmRefs::R($t2) + 2: $t1 := $t3 + 3: $t4 := copy($t1) + 4: $t0 := $t4 + 5: $t5 := move($t0) + 6: $t6 := move($t1) + 7: return $t6 +} diff --git a/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.move b/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.move index 95358d749e..8dada99bc3 100644 --- a/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.move +++ b/language/move-prover/bytecode/tests/eliminate_imm_refs/basic_test.move @@ -29,4 +29,11 @@ module 0x42::TestEliminateImmRefs { let r_ref = & r; test3(r_ref) } + + fun test5() : R { + let r = R {x: 3}; + let p = &r; + let _ = p; + r + } } diff --git a/language/move-prover/bytecode/tests/livevar/basic_test.exp b/language/move-prover/bytecode/tests/livevar/basic_test.exp index 4400b5a026..27758c11ae 100644 --- a/language/move-prover/bytecode/tests/livevar/basic_test.exp +++ b/language/move-prover/bytecode/tests/livevar/basic_test.exp @@ -152,20 +152,18 @@ fun TestLiveVars::test2($t0|b: bool): u64 { 3: $t7 := pack TestLiveVars::R($t6) # live vars: b, $t5, $t7 4: $t3 := $t5 - # live vars: b, r_ref, $t5, $t7 - 5: if ($t0) goto 6 else goto 9 - # live vars: $t5, $t7 + # live vars: b, r_ref, $t7 + 5: if ($t0) goto 6 else goto 8 + # live vars: $t7 6: label L0 - # live vars: $t5, $t7 - 7: destroy($t5) # live vars: $t7 - 8: $t3 := $t7 + 7: $t3 := $t7 # live vars: r_ref - 9: label L2 + 8: label L2 # live vars: r_ref - 10: $t8 := TestLiveVars::test1($t3) + 9: $t8 := TestLiveVars::test1($t3) # live vars: $t8 - 11: return $t8 + 10: return $t8 } @@ -200,43 +198,41 @@ fun TestLiveVars::test3($t0|n: u64, $t1|r_ref: TestLiveVars::R): u64 { # live vars: n, r_ref, $t5, $t7, $t8 6: $t9 := <($t8, $t0) # live vars: n, r_ref, $t5, $t7, $t9 - 7: if ($t9) goto 8 else goto 24 - # live vars: n, r_ref, $t5, $t7 + 7: if ($t9) goto 8 else goto 23 + # live vars: n, $t5, $t7 8: label L0 - # live vars: n, r_ref, $t5, $t7 - 9: destroy($t1) # live vars: n, $t5, $t7 - 10: $t10 := 2 + 9: $t10 := 2 # live vars: n, $t5, $t7, $t10 - 11: $t11 := /($t0, $t10) + 10: $t11 := /($t0, $t10) # live vars: n, $t5, $t7, $t11 - 12: $t12 := 0 + 11: $t12 := 0 # live vars: n, $t5, $t7, $t11, $t12 - 13: $t13 := ==($t11, $t12) + 12: $t13 := ==($t11, $t12) # live vars: n, $t5, $t7, $t13 - 14: if ($t13) goto 15 else goto 18 + 13: if ($t13) goto 14 else goto 17 # live vars: n, $t5, $t7 - 15: label L3 + 14: label L3 # live vars: n, $t5, $t7 - 16: $t1 := $t5 + 15: $t1 := $t5 # live vars: n, r_ref, $t5, $t7 - 17: goto 20 + 16: goto 19 # live vars: n, $t5, $t7 - 18: label L5 + 17: label L5 # live vars: n, $t5, $t7 - 19: $t1 := $t7 + 18: $t1 := $t7 # live vars: n, r_ref, $t5, $t7 - 20: label L6 + 19: label L6 # live vars: n, r_ref, $t5, $t7 - 21: $t14 := 1 + 20: $t14 := 1 # live vars: n, r_ref, $t5, $t7, $t14 - 22: $t0 := -($t0, $t14) + 21: $t0 := -($t0, $t14) # live vars: n, r_ref, $t5, $t7 - 23: goto 4 + 22: goto 4 # live vars: r_ref - 24: label L2 + 23: label L2 # live vars: r_ref - 25: $t15 := TestLiveVars::test1($t1) + 24: $t15 := TestLiveVars::test1($t1) # live vars: $t15 - 26: return $t15 + 25: return $t15 } diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.exp index be28cc6e9c..14fea56e3c 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.exp +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.exp @@ -1,2 +1,3 @@ Running Move unit tests -Test result: OK. Total tests: 0; passed: 0; failed: 0 +[ PASS ] 0x2::A::destroy +Test result: OK. Total tests: 1; passed: 1; failed: 0 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.move index 319b45e5d9..ac49ff3e12 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/destroy.move @@ -8,8 +8,7 @@ module 0x2::A { s.f2 } - // TODO (mengxu) there is a bug that tries to destroy a value instead of reference - // #[test] + #[test] public fun destroy(): S { let s = S { f1: true, f2: 42 }; let p = &s; From 28082f5fc4b1899947a2403f58cb9ffed9a969b7 Mon Sep 17 00:00:00 2001 From: uvd <386180127@qq.com> Date: Sat, 30 Jul 2022 22:57:08 +0800 Subject: [PATCH 019/169] upgrade rust toolchain 1.62.1 && edition 2021 && cargo clippy --fix (#275) * upgrade rust toolchain 1.62.0 && cargo clippy --fix * upgrade 2021 edition * fix lint * use cargo xfmt --- devtools/x-core/Cargo.toml | 2 +- devtools/x-lint/Cargo.toml | 2 +- devtools/x/Cargo.toml | 2 +- devtools/x/src/lint/guppy.rs | 13 ++++++------ language/benchmarks/Cargo.toml | 2 +- .../diem-framework/crates/cli/Cargo.toml | 2 +- .../crates/crypto-derive/Cargo.toml | 2 +- .../diem-framework/crates/crypto/Cargo.toml | 2 +- .../diem-framework/crates/natives/Cargo.toml | 2 +- language/evm/extract-ethereum-abi/Cargo.toml | 2 +- language/evm/move-ethereum-abi/Cargo.toml | 2 +- language/evm/move-to-yul/Cargo.toml | 2 +- .../evm/move-to-yul/src/abi_move_metadata.rs | 4 ++-- language/evm/move-to-yul/src/context.rs | 5 ++--- .../move-to-yul/src/dispatcher_generator.rs | 18 ++++++++-------- language/evm/move-to-yul/src/solidity_ty.rs | 2 +- language/evm/move-to-yul/src/vectors.rs | 2 +- language/evm/move-to-yul/tests/testsuite.rs | 16 ++++++++------ language/move-analyzer/Cargo.toml | 2 +- language/move-binary-format/Cargo.toml | 2 +- .../serializer-tests/Cargo.toml | 2 +- language/move-borrow-graph/Cargo.toml | 2 +- language/move-borrow-graph/src/references.rs | 2 +- language/move-bytecode-verifier/Cargo.toml | 2 +- .../bytecode-verifier-tests/Cargo.toml | 2 +- .../invalid-mutations/Cargo.toml | 2 +- .../transactional-tests/Cargo.toml | 2 +- language/move-command-line-common/Cargo.toml | 2 +- language/move-compiler/Cargo.toml | 2 +- language/move-compiler/src/diagnostics/mod.rs | 8 +++---- language/move-compiler/src/expansion/ast.rs | 2 +- .../move-compiler/src/naming/translate.rs | 2 +- .../transactional-tests/Cargo.toml | 2 +- language/move-core/types/Cargo.toml | 2 +- language/move-ir-compiler/Cargo.toml | 2 +- .../move-bytecode-source-map/Cargo.toml | 2 +- .../move-ir-to-bytecode/Cargo.toml | 2 +- .../move-ir-to-bytecode/src/compiler.rs | 15 +++++++------ .../move-ir-to-bytecode/syntax/Cargo.toml | 2 +- .../src/unit_tests/function_tests.rs | 7 ++++--- .../transactional-tests/Cargo.toml | 2 +- language/move-ir/types/Cargo.toml | 2 +- language/move-model/Cargo.toml | 2 +- language/move-prover/Cargo.toml | 2 +- .../move-prover/boogie-backend/Cargo.toml | 2 +- language/move-prover/bytecode/Cargo.toml | 2 +- language/move-prover/bytecode/src/lib.rs | 5 +++-- .../interpreter-testsuite/Cargo.toml | 2 +- language/move-prover/interpreter/Cargo.toml | 2 +- .../move-prover/interpreter/crypto/Cargo.toml | 2 +- language/move-prover/interpreter/src/lib.rs | 7 ++++--- language/move-prover/lab/Cargo.toml | 2 +- language/move-prover/lab/src/plot.rs | 3 +-- language/move-prover/move-abigen/Cargo.toml | 2 +- language/move-prover/move-docgen/Cargo.toml | 2 +- .../move-prover/move-docgen/src/docgen.rs | 9 +++++++- .../move-prover/move-errmapgen/Cargo.toml | 2 +- language/move-prover/mutation/Cargo.toml | 2 +- language/move-prover/test-utils/Cargo.toml | 2 +- .../move-prover/tools/spec-flatten/Cargo.toml | 2 +- language/move-symbol-pool/Cargo.toml | 2 +- language/move-vm/integration-tests/Cargo.toml | 2 +- language/move-vm/runtime/Cargo.toml | 2 +- language/move-vm/runtime/src/tracing.rs | 2 +- language/move-vm/test-utils/Cargo.toml | 2 +- .../move-vm/transactional-tests/Cargo.toml | 2 +- language/move-vm/types/Cargo.toml | 2 +- .../module-generation/Cargo.toml | 2 +- .../testing-infra/test-generation/Cargo.toml | 2 +- .../test-generation/src/transitions.rs | 6 +++--- .../transactional-test-runner/Cargo.toml | 2 +- .../src/framework.rs | 21 ++++++++++++------- language/tools/move-bytecode-utils/Cargo.toml | 2 +- .../tools/move-bytecode-viewer/Cargo.toml | 2 +- .../src/bytecode_viewer.rs | 2 +- language/tools/move-cli/Cargo.toml | 2 +- .../move-cli/src/sandbox/commands/test.rs | 7 ++++--- .../src/sandbox/utils/on_disk_state_view.rs | 2 +- language/tools/move-coverage/Cargo.toml | 2 +- language/tools/move-disassembler/Cargo.toml | 2 +- language/tools/move-explain/Cargo.toml | 2 +- language/tools/move-package/Cargo.toml | 2 +- .../tools/move-resource-viewer/Cargo.toml | 2 +- language/tools/move-unit-test/Cargo.toml | 2 +- .../tools/move-unit-test/src/test_reporter.rs | 2 +- .../tools/move-unit-test/src/test_runner.rs | 2 +- language/tools/read-write-set/Cargo.toml | 2 +- .../tools/read-write-set/dynamic/Cargo.toml | 2 +- .../tools/read-write-set/types/Cargo.toml | 2 +- rust-toolchain | 2 +- rustfmt.toml | 2 +- 91 files changed, 159 insertions(+), 137 deletions(-) diff --git a/devtools/x-core/Cargo.toml b/devtools/x-core/Cargo.toml index cad7367c3a..710b0b403a 100644 --- a/devtools/x-core/Cargo.toml +++ b/devtools/x-core/Cargo.toml @@ -3,7 +3,7 @@ name = "x-core" version = "0.1.0" authors = ["Diem Association "] description = "Core data structures used by x" -edition = "2018" +edition = "2021" publish = false license = "Apache-2.0" diff --git a/devtools/x-lint/Cargo.toml b/devtools/x-lint/Cargo.toml index 4174311b85..69ddfb7c08 100644 --- a/devtools/x-lint/Cargo.toml +++ b/devtools/x-lint/Cargo.toml @@ -3,7 +3,7 @@ name = "x-lint" version = "0.1.0" authors = ["Diem Association "] description = "Lint engine for x" -edition = "2018" +edition = "2021" publish = false license = "Apache-2.0" diff --git a/devtools/x/Cargo.toml b/devtools/x/Cargo.toml index 59596f3610..f4a0ab058f 100644 --- a/devtools/x/Cargo.toml +++ b/devtools/x/Cargo.toml @@ -3,7 +3,7 @@ name = "x" version = "0.1.0" authors = ["Diem Association "] description = "Diem extended cargo tasks" -edition = "2018" +edition = "2021" publish = false license = "Apache-2.0" diff --git a/devtools/x/src/lint/guppy.rs b/devtools/x/src/lint/guppy.rs index cc7e1534c3..fcb79f77b6 100644 --- a/devtools/x/src/lint/guppy.rs +++ b/devtools/x/src/lint/guppy.rs @@ -14,6 +14,7 @@ use guppy::{ }; use std::{ collections::{BTreeMap, HashMap}, + fmt::Write as FmtWrite, iter, }; use x_core::{WorkspaceStatus, XCoreContext}; @@ -270,9 +271,7 @@ impl<'cfg> ProjectLinter for DirectDepDups<'cfg> { if versions.len() > 1 { let mut msg = format!("duplicate direct dependency '{}':\n", direct_dep); for (version, packages) in versions { - msg.push_str(&format!(" * {} (", version)); - msg.push_str(&packages.join(", ")); - msg.push_str(")\n"); + writeln!(&mut msg, " * {} ({})", version, &packages.join(", ")).unwrap(); } out.write(LintLevel::Error, msg); } @@ -361,12 +360,14 @@ impl<'cfg> PackageLinter for OverlayFeatures<'cfg> { if !overlays.is_empty() { let mut msg = "overlay features enabled by default:\n".to_string(); for (from_feature, to_package, to_feature) in overlays { - msg.push_str(&format!( - " * {} -> {}/{}\n", + writeln!( + &mut msg, + " * {} -> {}/{}", feature_str(from_feature), to_package, feature_str(to_feature) - )); + ) + .unwrap(); } msg.push_str("Use a line in the [features] section instead.\n"); out.write(LintLevel::Error, msg); diff --git a/language/benchmarks/Cargo.toml b/language/benchmarks/Cargo.toml index 8398914568..c2becf96cb 100644 --- a/language/benchmarks/Cargo.toml +++ b/language/benchmarks/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/documentation/examples/diem-framework/crates/cli/Cargo.toml b/language/documentation/examples/diem-framework/crates/cli/Cargo.toml index 9cc4980d10..95a320833a 100644 --- a/language/documentation/examples/diem-framework/crates/cli/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/cli/Cargo.toml @@ -5,7 +5,7 @@ description = "CLI frontend for the Move compiler and VM (with Diem Framework)" authors = ["Diem Association "] license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/documentation/examples/diem-framework/crates/crypto-derive/Cargo.toml b/language/documentation/examples/diem-framework/crates/crypto-derive/Cargo.toml index efae300ae2..cd5d74589c 100644 --- a/language/documentation/examples/diem-framework/crates/crypto-derive/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/crypto-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "diem-crypto-derive" version = "0.0.3" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [lib] diff --git a/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml b/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml index 895d8bf24e..dd636356f9 100644 --- a/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/crypto/Cargo.toml @@ -3,7 +3,7 @@ name = "diem-crypto" version = "0.0.3" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/documentation/examples/diem-framework/crates/natives/Cargo.toml b/language/documentation/examples/diem-framework/crates/natives/Cargo.toml index f59df07096..cc2867982a 100644 --- a/language/documentation/examples/diem-framework/crates/natives/Cargo.toml +++ b/language/documentation/examples/diem-framework/crates/natives/Cargo.toml @@ -3,7 +3,7 @@ name = "diem-framework-natives" version = "0.0.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/evm/extract-ethereum-abi/Cargo.toml b/language/evm/extract-ethereum-abi/Cargo.toml index d40acabe04..7ae124f1be 100644 --- a/language/evm/extract-ethereum-abi/Cargo.toml +++ b/language/evm/extract-ethereum-abi/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Diem Association "] description = "Extract Etherem ABI" publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/evm/move-ethereum-abi/Cargo.toml b/language/evm/move-ethereum-abi/Cargo.toml index c837746ad9..329e78cec5 100644 --- a/language/evm/move-ethereum-abi/Cargo.toml +++ b/language/evm/move-ethereum-abi/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Diem Association "] description = "Move Ethereum ABI" publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/evm/move-to-yul/Cargo.toml b/language/evm/move-to-yul/Cargo.toml index 34f28a7dcf..40b2798ec6 100644 --- a/language/evm/move-to-yul/Cargo.toml +++ b/language/evm/move-to-yul/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Diem Association "] description = "Move Solidity Generator" publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/evm/move-to-yul/src/abi_move_metadata.rs b/language/evm/move-to-yul/src/abi_move_metadata.rs index d709309752..9d1b42908c 100644 --- a/language/evm/move-to-yul/src/abi_move_metadata.rs +++ b/language/evm/move-to-yul/src/abi_move_metadata.rs @@ -26,7 +26,7 @@ pub(crate) fn generate_abi_move_metadata(ctx: &Context, receive: bool, fallback: let st_env = ctx.env.get_struct(key.to_qualified_id()); event_map.insert( st_env.get_identifier().unwrap().to_string(), - from_event_sig(ctx.event_signature_map.borrow().get(&key).unwrap()), + from_event_sig(ctx.event_signature_map.borrow().get(key).unwrap()), ); } @@ -34,7 +34,7 @@ pub(crate) fn generate_abi_move_metadata(ctx: &Context, receive: bool, fallback: let mut func_map = BTreeMap::new(); for (key, (solidity_sig, attr)) in ctx.callable_function_map.borrow().iter() { let fun = ctx.env.get_function(key.to_qualified_id()); - let abi_sig = from_solidity_sig(&solidity_sig, Some(*attr), "function"); + let abi_sig = from_solidity_sig(solidity_sig, Some(*attr), "function"); func_map.insert(fun.get_identifier().to_string(), abi_sig); } diff --git a/language/evm/move-to-yul/src/context.rs b/language/evm/move-to-yul/src/context.rs index 7cc5776852..c4671c3841 100644 --- a/language/evm/move-to-yul/src/context.rs +++ b/language/evm/move-to-yul/src/context.rs @@ -354,8 +354,7 @@ impl<'a> Context<'a> { fn get_target_structs(&self, p: impl Fn(&StructEnv) -> bool) -> Vec> { self.env .get_modules() - .map(|m| m.into_structs().filter(|f| p(f))) - .flatten() + .flat_map(|m| m.into_structs().filter(|f| p(f))) .collect() } @@ -608,7 +607,7 @@ impl<'a> Context<'a> { .get_local_name(idx) .display(target.symbol_pool()) .to_string() - .replace("#", "_") + .replace('#', "_") } /// Make name for a result. diff --git a/language/evm/move-to-yul/src/dispatcher_generator.rs b/language/evm/move-to-yul/src/dispatcher_generator.rs index 64c9e5be29..2ecc93d8b8 100644 --- a/language/evm/move-to-yul/src/dispatcher_generator.rs +++ b/language/evm/move-to-yul/src/dispatcher_generator.rs @@ -261,8 +261,8 @@ impl Generator { /// Generate optional receive function. fn optional_receive(&mut self, ctx: &Context, receive: &Option>) -> bool { if let Some(receive) = receive { - ctx.check_no_generics(&receive); - if !attributes::is_payable_fun(&receive) { + ctx.check_no_generics(receive); + if !attributes::is_payable_fun(receive) { ctx.env .error(&receive.get_loc(), "receive function must be payable") } @@ -309,8 +309,8 @@ impl Generator { fallback: &Option>, ) { if let Some(fallback) = fallback { - ctx.check_no_generics(&fallback); - if !attributes::is_payable_fun(&fallback) { + ctx.check_no_generics(fallback); + if !attributes::is_payable_fun(fallback) { self.generate_call_value_check(ctx, REVERT_ERR_NON_PAYABLE_FUN); } let fun_id = &fallback @@ -560,7 +560,7 @@ impl Generator { ); }); head_pos += ty_size; - let memory_func = ctx.memory_store_builtin_fun(&move_ty); + let memory_func = ctx.memory_store_builtin_fun(move_ty); if local_typ_var.len() == 1 { gen.call_builtin( ctx, @@ -1454,7 +1454,7 @@ impl Generator { { let is_static = ty.is_static(); let local_typ_var = vec![ret_var[stack_pos].clone()]; - let memory_func = ctx.memory_load_builtin_fun(&move_ty); + let memory_func = ctx.memory_load_builtin_fun(move_ty); if local_typ_var.len() == 1 { emitln!( ctx.writer, @@ -1474,7 +1474,7 @@ impl Generator { ctx, &ty.clone(), &SignatureDataLocation::Memory, - &move_ty, + move_ty, sub_option.clone() ), local_typ_var[0].clone() @@ -1488,7 +1488,7 @@ impl Generator { ctx, &ty.clone(), &SignatureDataLocation::Memory, - &move_ty, + move_ty, sub_option.clone() ), local_typ_var[0].clone(), @@ -1507,7 +1507,7 @@ impl Generator { ctx, &ty.clone(), &SignatureDataLocation::Memory, - &move_ty, + move_ty, sub_option.clone() ), local_typ_var[0].clone() diff --git a/language/evm/move-to-yul/src/solidity_ty.rs b/language/evm/move-to-yul/src/solidity_ty.rs index 56b608bf22..0cb3799b18 100644 --- a/language/evm/move-to-yul/src/solidity_ty.rs +++ b/language/evm/move-to-yul/src/solidity_ty.rs @@ -398,7 +398,7 @@ impl SolidityType { let error_msg = "illegal type name"; return Err(anyhow!(error_msg)); } - ctx.check_or_create_struct_abi(&trimmed_ty_str) + ctx.check_or_create_struct_abi(trimmed_ty_str) } } diff --git a/language/evm/move-to-yul/src/vectors.rs b/language/evm/move-to-yul/src/vectors.rs index df3fe9f41d..551330d5b9 100644 --- a/language/evm/move-to-yul/src/vectors.rs +++ b/language/evm/move-to-yul/src/vectors.rs @@ -1051,7 +1051,7 @@ fn define_destroy_empty_fun( /// Generate equality method for the vector type. pub(crate) fn equality_fun(gen: &mut Generator, ctx: &Context, ty: &Type) { - let elem_type = get_elem_type(&ty).unwrap(); + let elem_type = get_elem_type(ty).unwrap(); if ctx.type_allocates_memory(&elem_type) { emitln!( ctx.writer, diff --git a/language/evm/move-to-yul/tests/testsuite.rs b/language/evm/move-to-yul/tests/testsuite.rs index 651eb3c264..f782f09153 100644 --- a/language/evm/move-to-yul/tests/testsuite.rs +++ b/language/evm/move-to-yul/tests/testsuite.rs @@ -19,6 +19,7 @@ use move_to_yul::{generator::Generator, options::Options}; use primitive_types::{H160, U256}; use std::{ collections::BTreeMap, + fmt::Write, path::{Path, PathBuf}, }; @@ -116,16 +117,19 @@ fn run_tests( let mut res = String::new(); res.push_str("!! Unit tests\n\n"); for (fun, source) in test_cases { - res.push_str(&format!( - "// test of {}\n", + writeln!( + &mut res, + "// test of {}", env.get_function(*fun).get_full_name_str() - )); + ) + .unwrap(); res.push_str(source); - res.push_str(&format!( - "===> Test result of {}: {}\n\n", + writeln!( + &mut res, + "===> Test result of {}: {}\n", env.get_function(*fun).get_full_name_str(), execute_test(env, source)? - )); + )?; } Ok(res) } diff --git a/language/move-analyzer/Cargo.toml b/language/move-analyzer/Cargo.toml index c15d5ea4de..ea1ca98156 100644 --- a/language/move-analyzer/Cargo.toml +++ b/language/move-analyzer/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-binary-format/Cargo.toml b/language/move-binary-format/Cargo.toml index 0ae756af37..25ea04cdf2 100644 --- a/language/move-binary-format/Cargo.toml +++ b/language/move-binary-format/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = ["crates-io"] -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-binary-format/serializer-tests/Cargo.toml b/language/move-binary-format/serializer-tests/Cargo.toml index a7a85baba6..1cd9077992 100644 --- a/language/move-binary-format/serializer-tests/Cargo.toml +++ b/language/move-binary-format/serializer-tests/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dev-dependencies] proptest = "1.0.0" diff --git a/language/move-borrow-graph/Cargo.toml b/language/move-borrow-graph/Cargo.toml index 5e2285b2ef..891b9be448 100644 --- a/language/move-borrow-graph/Cargo.toml +++ b/language/move-borrow-graph/Cargo.toml @@ -3,5 +3,5 @@ name = "move-borrow-graph" version = "0.0.1" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" diff --git a/language/move-borrow-graph/src/references.rs b/language/move-borrow-graph/src/references.rs index a420d56032..a1d1090f9a 100644 --- a/language/move-borrow-graph/src/references.rs +++ b/language/move-borrow-graph/src/references.rs @@ -229,7 +229,7 @@ impl Debug for BorrowEdge { // Iteration //********************************************************************************************** -impl<'a, Loc: Copy, Lbl: Clone + Ord> IntoIterator for BorrowEdgeSet { +impl IntoIterator for BorrowEdgeSet { type Item = BorrowEdge; type IntoIter = std::collections::btree_set::IntoIter>; diff --git a/language/move-bytecode-verifier/Cargo.toml b/language/move-bytecode-verifier/Cargo.toml index c85640fbeb..5049b4be10 100644 --- a/language/move-bytecode-verifier/Cargo.toml +++ b/language/move-bytecode-verifier/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml b/language/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml index 7ba9a30293..8b256d6d88 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dev-dependencies] petgraph = "0.5.1" diff --git a/language/move-bytecode-verifier/invalid-mutations/Cargo.toml b/language/move-bytecode-verifier/invalid-mutations/Cargo.toml index 5f6fc2617c..ed46af714c 100644 --- a/language/move-bytecode-verifier/invalid-mutations/Cargo.toml +++ b/language/move-bytecode-verifier/invalid-mutations/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "invalid-mutations" version = "0.1.0" -edition = "2018" +edition = "2021" authors = ["Diem Association "] description = "Diem invalid mutations" repository = "https://github.com/diem/diem" diff --git a/language/move-bytecode-verifier/transactional-tests/Cargo.toml b/language/move-bytecode-verifier/transactional-tests/Cargo.toml index 403f8f1b8f..e30e2600e0 100644 --- a/language/move-bytecode-verifier/transactional-tests/Cargo.toml +++ b/language/move-bytecode-verifier/transactional-tests/Cargo.toml @@ -3,7 +3,7 @@ name = "bytecode-verifier-transactional-tests" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dev-dependencies] diff --git a/language/move-command-line-common/Cargo.toml b/language/move-command-line-common/Cargo.toml index b46997d364..361d3431c2 100644 --- a/language/move-command-line-common/Cargo.toml +++ b/language/move-command-line-common/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-compiler/Cargo.toml b/language/move-compiler/Cargo.toml index 38cffc1e0b..0d266e48b2 100644 --- a/language/move-compiler/Cargo.toml +++ b/language/move-compiler/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" authors = ["Diem Association "] description = "The definition of the Move source language, and its compiler" publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-compiler/src/diagnostics/mod.rs b/language/move-compiler/src/diagnostics/mod.rs index 166699ad00..ae49b4c061 100644 --- a/language/move-compiler/src/diagnostics/mod.rs +++ b/language/move-compiler/src/diagnostics/mod.rs @@ -320,8 +320,8 @@ impl Diagnostic { macro_rules! diag { ($code: expr, $primary: expr $(,)?) => {{ #[allow(unused)] - use crate::diagnostics::codes::*; - crate::diagnostics::Diagnostic::new( + use $crate::diagnostics::codes::*; + $crate::diagnostics::Diagnostic::new( $code, $primary, std::iter::empty::<(move_ir_types::location::Loc, String)>(), @@ -330,8 +330,8 @@ macro_rules! diag { }}; ($code: expr, $primary: expr, $($secondary: expr),+ $(,)?) => {{ #[allow(unused)] - use crate::diagnostics::codes::*; - crate::diagnostics::Diagnostic::new( + use $crate::diagnostics::codes::*; + $crate::diagnostics::Diagnostic::new( $code, $primary, vec![$($secondary, )*], diff --git a/language/move-compiler/src/expansion/ast.rs b/language/move-compiler/src/expansion/ast.rs index b262a41201..4a0458e7f6 100644 --- a/language/move-compiler/src/expansion/ast.rs +++ b/language/move-compiler/src/expansion/ast.rs @@ -725,7 +725,7 @@ impl Iterator for AbilitySetIntoIter { } } -impl<'a> IntoIterator for AbilitySet { +impl IntoIterator for AbilitySet { type Item = Ability; type IntoIter = AbilitySetIntoIter; diff --git a/language/move-compiler/src/naming/translate.rs b/language/move-compiler/src/naming/translate.rs index 353274b3f4..5c7e30d258 100644 --- a/language/move-compiler/src/naming/translate.rs +++ b/language/move-compiler/src/naming/translate.rs @@ -506,7 +506,7 @@ fn function( acquires, body, }; - fake_natives::function(&mut context.env, module_opt, name, &f); + fake_natives::function(context.env, module_opt, name, &f); f } diff --git a/language/move-compiler/transactional-tests/Cargo.toml b/language/move-compiler/transactional-tests/Cargo.toml index deae23755f..241db23c7f 100644 --- a/language/move-compiler/transactional-tests/Cargo.toml +++ b/language/move-compiler/transactional-tests/Cargo.toml @@ -3,7 +3,7 @@ name = "move-compiler-transactional-tests" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dev-dependencies] diff --git a/language/move-core/types/Cargo.toml b/language/move-core/types/Cargo.toml index c5f48be883..cc71459fdb 100644 --- a/language/move-core/types/Cargo.toml +++ b/language/move-core/types/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = ["crates-io"] -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-ir-compiler/Cargo.toml b/language/move-ir-compiler/Cargo.toml index 79387bae2e..8b3513a8d8 100644 --- a/language/move-ir-compiler/Cargo.toml +++ b/language/move-ir-compiler/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-ir-compiler/move-bytecode-source-map/Cargo.toml b/language/move-ir-compiler/move-bytecode-source-map/Cargo.toml index 7a20d53e1c..9f5bbaacfc 100644 --- a/language/move-ir-compiler/move-bytecode-source-map/Cargo.toml +++ b/language/move-ir-compiler/move-bytecode-source-map/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Diem Association "] license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-ir-compiler/move-ir-to-bytecode/Cargo.toml b/language/move-ir-compiler/move-ir-to-bytecode/Cargo.toml index 755d11ef40..51b95fde27 100644 --- a/language/move-ir-compiler/move-ir-to-bytecode/Cargo.toml +++ b/language/move-ir-compiler/move-ir-to-bytecode/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-ir-compiler/move-ir-to-bytecode/src/compiler.rs b/language/move-ir-compiler/move-ir-to-bytecode/src/compiler.rs index e80badc417..29da556027 100644 --- a/language/move-ir-compiler/move-ir-to-bytecode/src/compiler.rs +++ b/language/move-ir-compiler/move-ir-to-bytecode/src/compiler.rs @@ -27,6 +27,7 @@ use std::{ hash_map::Entry::{Occupied, Vacant}, BTreeSet, HashMap, HashSet, }, + fmt::Write, }; macro_rules! record_src_loc { @@ -195,24 +196,26 @@ fn label_verification_error( ) -> Result<()> { let mut message = "Invalid block labels".to_string(); if !redeclared.is_empty() { - message.push_str(&format!( + write!( + &mut message, ", labels were declared twice ({})", redeclared .iter() .map(|l| l.to_string()) .collect::>() - .join(", "), - )); + .join(", ") + )?; } if !undeclared.is_empty() { - message.push_str(&format!( + write!( + &mut message, ", labels were used without being declared ({})", undeclared .iter() .map(|l| l.to_string()) .collect::>() - .join(", "), - )); + .join(", ") + )?; } bail!(message); } diff --git a/language/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml b/language/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml index 0f5d7a4377..0180317793 100644 --- a/language/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml +++ b/language/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/move-ir-compiler/src/unit_tests/function_tests.rs b/language/move-ir-compiler/src/unit_tests/function_tests.rs index 5fa726968e..42dc9cecc9 100644 --- a/language/move-ir-compiler/src/unit_tests/function_tests.rs +++ b/language/move-ir-compiler/src/unit_tests/function_tests.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::unit_tests::testutils::compile_module_string; +use std::fmt::Write; fn generate_function(name: &str, num_formals: usize, num_locals: usize) -> String { let mut code = format!("public {}(", name); @@ -10,7 +11,7 @@ fn generate_function(name: &str, num_formals: usize, num_locals: usize) -> Strin code.reserve(30 * (num_formals + num_locals)); for i in 0..num_formals { - code.push_str(&format!("formal_{}: u64", i)); + write!(&mut code, "formal_{}: u64", i).unwrap(); if i < num_formals - 1 { code.push_str(", "); } @@ -19,11 +20,11 @@ fn generate_function(name: &str, num_formals: usize, num_locals: usize) -> Strin code.push_str(") {\n"); for i in 0..num_locals { - code.push_str(&format!("let x_{}: u64;\n", i)); + writeln!(&mut code, "let x_{}: u64;", i).unwrap(); } code.push_str("label b0:\n"); for i in 0..num_locals { - code.push_str(&format!("x_{} = {};\n", i, i)); + writeln!(&mut code, "x_{} = {};", i, i).unwrap(); } code.push_str("return;"); diff --git a/language/move-ir-compiler/transactional-tests/Cargo.toml b/language/move-ir-compiler/transactional-tests/Cargo.toml index 0fdf6a8d63..122e04c286 100644 --- a/language/move-ir-compiler/transactional-tests/Cargo.toml +++ b/language/move-ir-compiler/transactional-tests/Cargo.toml @@ -3,7 +3,7 @@ name = "move-ir-compiler-transactional-tests" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dev-dependencies] diff --git a/language/move-ir/types/Cargo.toml b/language/move-ir/types/Cargo.toml index 67f9173e89..3839631e1c 100644 --- a/language/move-ir/types/Cargo.toml +++ b/language/move-ir/types/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/language/move-model/Cargo.toml b/language/move-model/Cargo.toml index ef99df1a2b..1204e36927 100644 --- a/language/move-model/Cargo.toml +++ b/language/move-model/Cargo.toml @@ -3,7 +3,7 @@ name = "move-model" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/Cargo.toml b/language/move-prover/Cargo.toml index fb7369fbdc..2ae6e48cc9 100644 --- a/language/move-prover/Cargo.toml +++ b/language/move-prover/Cargo.toml @@ -3,7 +3,7 @@ name = "move-prover" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/boogie-backend/Cargo.toml b/language/move-prover/boogie-backend/Cargo.toml index 2a0256eb23..7198c28970 100644 --- a/language/move-prover/boogie-backend/Cargo.toml +++ b/language/move-prover/boogie-backend/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Move prover Boogie backend" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] async-trait = "0.1.42" diff --git a/language/move-prover/bytecode/Cargo.toml b/language/move-prover/bytecode/Cargo.toml index 1ee878e6ac..e802d8b236 100644 --- a/language/move-prover/bytecode/Cargo.toml +++ b/language/move-prover/bytecode/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] move-model = { path = "../../move-model" } diff --git a/language/move-prover/bytecode/src/lib.rs b/language/move-prover/bytecode/src/lib.rs index 3599d63c7d..8c01cbf6a8 100644 --- a/language/move-prover/bytecode/src/lib.rs +++ b/language/move-prover/bytecode/src/lib.rs @@ -6,6 +6,7 @@ use crate::function_target_pipeline::FunctionTargetsHolder; use move_model::model::GlobalEnv; +use std::fmt::Write; pub mod access_path; pub mod access_path_trie; @@ -54,13 +55,13 @@ pub fn print_targets_for_test( targets: &FunctionTargetsHolder, ) -> String { let mut text = String::new(); - text.push_str(&format!("============ {} ================\n", header)); + writeln!(&mut text, "============ {} ================", header).unwrap(); for module_env in env.get_modules() { for func_env in module_env.get_functions() { for (variant, target) in targets.get_targets(&func_env) { if !target.data.code.is_empty() || target.func_env.is_native_or_intrinsic() { target.register_annotation_formatters_for_test(); - text += &format!("\n[variant {}]\n{}\n", variant, target); + writeln!(&mut text, "\n[variant {}]\n{}", variant, target).unwrap(); } } } diff --git a/language/move-prover/interpreter-testsuite/Cargo.toml b/language/move-prover/interpreter-testsuite/Cargo.toml index 31fec11941..83a268cdc2 100644 --- a/language/move-prover/interpreter-testsuite/Cargo.toml +++ b/language/move-prover/interpreter-testsuite/Cargo.toml @@ -3,7 +3,7 @@ name = "bytecode-interpreter-testsuite" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dev-dependencies] diff --git a/language/move-prover/interpreter/Cargo.toml b/language/move-prover/interpreter/Cargo.toml index ce71900c71..40cd3a0019 100644 --- a/language/move-prover/interpreter/Cargo.toml +++ b/language/move-prover/interpreter/Cargo.toml @@ -3,7 +3,7 @@ name = "move-stackless-bytecode-interpreter" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/interpreter/crypto/Cargo.toml b/language/move-prover/interpreter/crypto/Cargo.toml index e703ce5d63..db309a5a83 100644 --- a/language/move-prover/interpreter/crypto/Cargo.toml +++ b/language/move-prover/interpreter/crypto/Cargo.toml @@ -3,7 +3,7 @@ name = "bytecode-interpreter-crypto" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/interpreter/src/lib.rs b/language/move-prover/interpreter/src/lib.rs index 955f309055..9995431a51 100644 --- a/language/move-prover/interpreter/src/lib.rs +++ b/language/move-prover/interpreter/src/lib.rs @@ -1,10 +1,10 @@ // Copyright (c) The Diem Core Contributors // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 - use anyhow::{bail, Result}; use clap::Parser; use codespan_reporting::{diagnostic::Severity, term::termcolor::Buffer}; +use std::fmt::Write; use move_binary_format::errors::{Location, PartialVMError, PartialVMResult, VMResult}; use move_core_types::{ @@ -202,7 +202,7 @@ impl<'env> StacklessBytecodeInterpreter<'env> { for func_env in module_env.get_functions() { for (variant, target) in targets.get_targets(&func_env) { target.register_annotation_formatters_for_test(); - text += &format!("[variant {}]\n{}\n", variant, target); + writeln!(&mut text, "[variant {}]\n{}", variant, target).unwrap(); } } } @@ -339,7 +339,8 @@ fn verbose_stepwise_processing( for (_, target) in targets.get_targets(&func_env) { if !target.data.code.is_empty() { target.register_annotation_formatters_for_test(); - text += &format!("[{}-{}]\n{}\n", step, name, target); + + writeln!(&mut text, "[{}-{}]\n{}", step, name, target).unwrap(); } } } diff --git a/language/move-prover/lab/Cargo.toml b/language/move-prover/lab/Cargo.toml index e6ad76c0af..1457db23a7 100644 --- a/language/move-prover/lab/Cargo.toml +++ b/language/move-prover/lab/Cargo.toml @@ -3,7 +3,7 @@ name = "prover-lab" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/lab/src/plot.rs b/language/move-prover/lab/src/plot.rs index 58111523c8..df74cf1ac2 100644 --- a/language/move-prover/lab/src/plot.rs +++ b/language/move-prover/lab/src/plot.rs @@ -155,8 +155,7 @@ pub fn plot_benchmarks_to_file(fname: &str, benchmarks: &[Benchmark]) -> anyhow: let data_points = joined.len() as u32; let max_duration = joined .iter() - .map(|(_, e)| e.iter().map(|(_, d)| *d)) - .flatten() + .flat_map(|(_, e)| e.iter().map(|(_, d)| *d)) .filter_map(|r| { if let Result::Duration(d) | Result::Error(d) = r { Some(d) diff --git a/language/move-prover/move-abigen/Cargo.toml b/language/move-prover/move-abigen/Cargo.toml index 5a28aaf10b..7d4f5c68b0 100644 --- a/language/move-prover/move-abigen/Cargo.toml +++ b/language/move-prover/move-abigen/Cargo.toml @@ -3,7 +3,7 @@ name = "move-abigen" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/move-docgen/Cargo.toml b/language/move-prover/move-docgen/Cargo.toml index 21084f1aeb..ac51fa3b11 100644 --- a/language/move-prover/move-docgen/Cargo.toml +++ b/language/move-prover/move-docgen/Cargo.toml @@ -3,7 +3,7 @@ name = "move-docgen" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/move-docgen/src/docgen.rs b/language/move-prover/move-docgen/src/docgen.rs index e6ebd477f3..29365f6a52 100644 --- a/language/move-prover/move-docgen/src/docgen.rs +++ b/language/move-prover/move-docgen/src/docgen.rs @@ -26,6 +26,7 @@ use serde::{Deserialize, Serialize}; use std::{ cell::RefCell, collections::{BTreeMap, BTreeSet, VecDeque}, + fmt::Write as FmtWrite, fs::{self, File}, io::{Read, Write}, path::{Path, PathBuf}, @@ -1467,7 +1468,13 @@ impl<'env> Docgen<'env> { "Missing backtick found in {} while generating documentation for the following text: \"{}\"", self.current_module.as_ref().unwrap().get_name().display_full(self.env.symbol_pool()), text, ); - decorated_text += &format!("{}", self.decorate_code(&code)); + + write!( + &mut decorated_text, + "{}", + self.decorate_code(&code) + ) + .unwrap() } } else { decorated_text.push(chr); diff --git a/language/move-prover/move-errmapgen/Cargo.toml b/language/move-prover/move-errmapgen/Cargo.toml index 05754cf803..6ec7e33e79 100644 --- a/language/move-prover/move-errmapgen/Cargo.toml +++ b/language/move-prover/move-errmapgen/Cargo.toml @@ -3,7 +3,7 @@ name = "move-errmapgen" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/mutation/Cargo.toml b/language/move-prover/mutation/Cargo.toml index 77d4c4e5f1..9119f17d88 100644 --- a/language/move-prover/mutation/Cargo.toml +++ b/language/move-prover/mutation/Cargo.toml @@ -3,7 +3,7 @@ name = "prover-mutation" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-prover/test-utils/Cargo.toml b/language/move-prover/test-utils/Cargo.toml index d632191aee..35f072e97d 100644 --- a/language/move-prover/test-utils/Cargo.toml +++ b/language/move-prover/test-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "move-prover-test-utils" version = "0.1.0" authors = ["Diem Association "] -edition = "2018" +edition = "2021" publish = false license = "Apache-2.0" diff --git a/language/move-prover/tools/spec-flatten/Cargo.toml b/language/move-prover/tools/spec-flatten/Cargo.toml index a24c5b9c96..2f974e4e67 100644 --- a/language/move-prover/tools/spec-flatten/Cargo.toml +++ b/language/move-prover/tools/spec-flatten/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Diem Association "] description = "Formal specification flattening tool" publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dependencies] diff --git a/language/move-symbol-pool/Cargo.toml b/language/move-symbol-pool/Cargo.toml index 6cc5b14748..db132c8990 100644 --- a/language/move-symbol-pool/Cargo.toml +++ b/language/move-symbol-pool/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] once_cell = "1.7.2" diff --git a/language/move-vm/integration-tests/Cargo.toml b/language/move-vm/integration-tests/Cargo.toml index 67b82cf73e..47cf1da438 100644 --- a/language/move-vm/integration-tests/Cargo.toml +++ b/language/move-vm/integration-tests/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/language/move-vm/runtime/Cargo.toml b/language/move-vm/runtime/Cargo.toml index df81c5a70e..2517f3e66c 100644 --- a/language/move-vm/runtime/Cargo.toml +++ b/language/move-vm/runtime/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/language/move-vm/runtime/src/tracing.rs b/language/move-vm/runtime/src/tracing.rs index 0a0c6abc03..b016879c9b 100644 --- a/language/move-vm/runtime/src/tracing.rs +++ b/language/move-vm/runtime/src/tracing.rs @@ -95,7 +95,7 @@ macro_rules! trace { ($function_desc:expr, $locals:expr, $pc:expr, $instr:tt, $resolver:expr, $interp:expr) => { // Only include this code in debug releases #[cfg(any(debug_assertions, feature = "debugging"))] - crate::tracing::trace( + $crate::tracing::trace( &$function_desc, $locals, $pc, diff --git a/language/move-vm/test-utils/Cargo.toml b/language/move-vm/test-utils/Cargo.toml index 809c23345c..23426b6f56 100644 --- a/language/move-vm/test-utils/Cargo.toml +++ b/language/move-vm/test-utils/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/language/move-vm/transactional-tests/Cargo.toml b/language/move-vm/transactional-tests/Cargo.toml index 03777ae5d3..d29d297039 100644 --- a/language/move-vm/transactional-tests/Cargo.toml +++ b/language/move-vm/transactional-tests/Cargo.toml @@ -3,7 +3,7 @@ name = "move-vm-transactional-tests" version = "0.1.0" authors = ["Diem Association "] publish = false -edition = "2018" +edition = "2021" license = "Apache-2.0" [dev-dependencies] diff --git a/language/move-vm/types/Cargo.toml b/language/move-vm/types/Cargo.toml index 1ac48f4893..3c7309abf2 100644 --- a/language/move-vm/types/Cargo.toml +++ b/language/move-vm/types/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] once_cell = "1.7.2" diff --git a/language/testing-infra/module-generation/Cargo.toml b/language/testing-infra/module-generation/Cargo.toml index 3b4e4611c8..c3b1cb5459 100644 --- a/language/testing-infra/module-generation/Cargo.toml +++ b/language/testing-infra/module-generation/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] rand = "0.8.3" diff --git a/language/testing-infra/test-generation/Cargo.toml b/language/testing-infra/test-generation/Cargo.toml index 6834936146..7e1366721c 100644 --- a/language/testing-infra/test-generation/Cargo.toml +++ b/language/testing-infra/test-generation/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] rand = "0.8.3" diff --git a/language/testing-infra/test-generation/src/transitions.rs b/language/testing-infra/test-generation/src/transitions.rs index cd969fefca..6b19fdff3a 100644 --- a/language/testing-infra/test-generation/src/transitions.rs +++ b/language/testing-infra/test-generation/src/transitions.rs @@ -1350,16 +1350,16 @@ macro_rules! state_never { #[macro_export] macro_rules! state_stack_bin_op { (#left) => { - Box::new(move |state| stack_bin_op(state, crate::transitions::StackBinOpResult::Left)) + Box::new(move |state| stack_bin_op(state, $crate::transitions::StackBinOpResult::Left)) }; (#right) => { - Box::new(move |state| stack_bin_op(state, crate::transitions::StackBinOpResult::Right)) + Box::new(move |state| stack_bin_op(state, $crate::transitions::StackBinOpResult::Right)) }; () => { state_stack_bin_op!(#left) }; ($e: expr) => { - Box::new(move |state| stack_bin_op(state, crate::transitions::StackBinOpResult::Other($e))) + Box::new(move |state| stack_bin_op(state, $crate::transitions::StackBinOpResult::Other($e))) } } diff --git a/language/testing-infra/transactional-test-runner/Cargo.toml b/language/testing-infra/transactional-test-runner/Cargo.toml index 798ecae63d..cb99bbcf4d 100644 --- a/language/testing-infra/transactional-test-runner/Cargo.toml +++ b/language/testing-infra/transactional-test-runner/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/testing-infra/transactional-test-runner/src/framework.rs b/language/testing-infra/transactional-test-runner/src/framework.rs index 7ed6121700..63cca7ccbe 100644 --- a/language/testing-infra/transactional-test-runner/src/framework.rs +++ b/language/testing-infra/transactional-test-runner/src/framework.rs @@ -41,7 +41,7 @@ use move_vm_runtime::session::SerializedReturnValues; use rayon::iter::Either; use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, - fmt::Debug, + fmt::{Debug, Write as FmtWrite}, io::Write, path::Path, }; @@ -667,11 +667,13 @@ where .collect::>(); assert!(!tasks.is_empty()); let num_tasks = tasks.len(); - output.push_str(&format!( - "processed {} task{}\n", + writeln!( + &mut output, + "processed {} task{}", num_tasks, if num_tasks > 1 { "s" } else { "" } - )); + ) + .unwrap(); let first_task = tasks.pop_front().unwrap(); let init_opt = match &first_task.command { @@ -687,7 +689,7 @@ where let (mut adapter, result_opt) = Adapter::init(default_syntax, fully_compiled_program_opt, init_opt); if let Some(result) = result_opt { - output.push_str(&format!("\ninit:\n{}\n", result)) + writeln!(output, "\ninit:\n{}", result)?; } for task in tasks { handle_known_task(&mut output, &mut adapter, task); @@ -720,10 +722,13 @@ fn handle_known_task<'a, Adapter: MoveTestAdapter<'a>>( Err(e) => format!("Error: {}", e), }; assert!(!result_string.is_empty()); - output.push_str(&format!( - "\ntask {} '{}'. lines {}-{}:\n{}\n", + + writeln!( + output, + "\ntask {} '{}'. lines {}-{}:\n{}", task_number, task_name, start_line, stop_line, result_string - )); + ) + .unwrap(); } fn handle_expected_output(test_path: &Path, output: impl AsRef) -> Result<()> { diff --git a/language/tools/move-bytecode-utils/Cargo.toml b/language/tools/move-bytecode-utils/Cargo.toml index f42c6d15ec..fbf52faf22 100644 --- a/language/tools/move-bytecode-utils/Cargo.toml +++ b/language/tools/move-bytecode-utils/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/move-bytecode-viewer/Cargo.toml b/language/tools/move-bytecode-viewer/Cargo.toml index 9dad79f75e..43b921483c 100644 --- a/language/tools/move-bytecode-viewer/Cargo.toml +++ b/language/tools/move-bytecode-viewer/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Explore Move bytecode and how the source code compiles to it" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] clap = { version = "3.1.8", features = ["derive"] } diff --git a/language/tools/move-bytecode-viewer/src/bytecode_viewer.rs b/language/tools/move-bytecode-viewer/src/bytecode_viewer.rs index 7279cab34d..4abbcabfdb 100644 --- a/language/tools/move-bytecode-viewer/src/bytecode_viewer.rs +++ b/language/tools/move-bytecode-viewer/src/bytecode_viewer.rs @@ -107,6 +107,6 @@ impl LeftScreen for BytecodeViewer<'_> { } fn backing_string(&self) -> String { - self.lines.join("\n").replace("\t", " ") + self.lines.join("\n").replace('\t', " ") } } diff --git a/language/tools/move-cli/Cargo.toml b/language/tools/move-cli/Cargo.toml index c948568968..efaca163b1 100644 --- a/language/tools/move-cli/Cargo.toml +++ b/language/tools/move-cli/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/move-cli/src/sandbox/commands/test.rs b/language/tools/move-cli/src/sandbox/commands/test.rs index 897a8f8f82..e7c3a8a426 100644 --- a/language/tools/move-cli/src/sandbox/commands/test.rs +++ b/language/tools/move-cli/src/sandbox/commands/test.rs @@ -20,6 +20,7 @@ use move_package::{ use std::{ collections::{BTreeMap, HashMap}, env, + fmt::Write as FmtWrite, fs::{self, File}, io::{self, BufRead, Write}, path::{Path, PathBuf}, @@ -223,7 +224,7 @@ pub fn run_one( for args_line in args_file { let args_line = args_line?; - if let Some(external_cmd) = args_line.strip_prefix(">") { + if let Some(external_cmd) = args_line.strip_prefix('>') { let external_cmd = external_cmd.trim_start(); let mut cmd_iter = external_cmd.split_ascii_whitespace(); @@ -238,7 +239,7 @@ pub fn run_one( } let cmd_output = command.output()?; - output += &format!("External Command `{}`:\n", external_cmd); + writeln!(&mut output, "External Command `{}`:", external_cmd)?; output += std::str::from_utf8(&cmd_output.stdout)?; output += std::str::from_utf8(&cmd_output.stderr)?; @@ -269,7 +270,7 @@ pub fn run_one( } let cmd_output = cli_command_template().args(args_iter).output()?; - output += &format!("Command `{}`:\n", args_line); + writeln!(&mut output, "Command `{}`:", args_line)?; output += std::str::from_utf8(&cmd_output.stdout)?; output += std::str::from_utf8(&cmd_output.stderr)?; } diff --git a/language/tools/move-cli/src/sandbox/utils/on_disk_state_view.rs b/language/tools/move-cli/src/sandbox/utils/on_disk_state_view.rs index bb3cb5d4db..9bd7246a02 100644 --- a/language/tools/move-cli/src/sandbox/utils/on_disk_state_view.rs +++ b/language/tools/move-cli/src/sandbox/utils/on_disk_state_view.rs @@ -138,7 +138,7 @@ impl OnDiskStateView { return None; } let name = Identifier::new(p.file_stem().unwrap().to_str().unwrap()).unwrap(); - match p.parent().map(|parent| parent.parent()).flatten() { + match p.parent().and_then(|parent| parent.parent()) { Some(parent) => { let addr = AccountAddress::from_hex_literal(parent.file_stem().unwrap().to_str().unwrap()) diff --git a/language/tools/move-coverage/Cargo.toml b/language/tools/move-coverage/Cargo.toml index 89fcaaec5a..5aca8e138e 100644 --- a/language/tools/move-coverage/Cargo.toml +++ b/language/tools/move-coverage/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] once_cell = "1.7.2" diff --git a/language/tools/move-disassembler/Cargo.toml b/language/tools/move-disassembler/Cargo.toml index ec4587992a..3553844ebd 100644 --- a/language/tools/move-disassembler/Cargo.toml +++ b/language/tools/move-disassembler/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Print a human-readable version of Move bytecode (.mv files)" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/move-explain/Cargo.toml b/language/tools/move-explain/Cargo.toml index 8f9742396a..824cefdfac 100644 --- a/language/tools/move-explain/Cargo.toml +++ b/language/tools/move-explain/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] clap = { version = "3.1.8", features = ["derive"] } diff --git a/language/tools/move-package/Cargo.toml b/language/tools/move-package/Cargo.toml index 3fbd69206d..4cb647e676 100644 --- a/language/tools/move-package/Cargo.toml +++ b/language/tools/move-package/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Diem Association "] description = "Package and build system for Move code" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] toml = "0.5.8" diff --git a/language/tools/move-resource-viewer/Cargo.toml b/language/tools/move-resource-viewer/Cargo.toml index c4dcb2bb15..427b7c684a 100644 --- a/language/tools/move-resource-viewer/Cargo.toml +++ b/language/tools/move-resource-viewer/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] bcs = "0.1.2" diff --git a/language/tools/move-unit-test/Cargo.toml b/language/tools/move-unit-test/Cargo.toml index 8cfcf0d34b..bf1bed8167 100644 --- a/language/tools/move-unit-test/Cargo.toml +++ b/language/tools/move-unit-test/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/move-unit-test/src/test_reporter.rs b/language/tools/move-unit-test/src/test_reporter.rs index 348222d658..2d074b3099 100644 --- a/language/tools/move-unit-test/src/test_reporter.rs +++ b/language/tools/move-unit-test/src/test_reporter.rs @@ -528,7 +528,7 @@ impl TestResults { "│ {}", test_failure .render_error(&self.test_plan) - .replace("\n", "\n│ ") + .replace('\n', "\n│ ") )?; writeln!(writer.lock().unwrap(), "└──────────────────\n")?; } diff --git a/language/tools/move-unit-test/src/test_runner.rs b/language/tools/move-unit-test/src/test_runner.rs index 0c442951f0..547c7cd2a4 100644 --- a/language/tools/move-unit-test/src/test_runner.rs +++ b/language/tools/move-unit-test/src/test_runner.rs @@ -122,7 +122,7 @@ fn print_resources_and_extensions( writeln!( &mut buf, "\t{}", - format!("=> {}", annotator.view_resource(tag, resource)?).replace("\n", "\n\t") + format!("=> {}", annotator.view_resource(tag, resource)?).replace('\n', "\n\t") )?; } } diff --git a/language/tools/read-write-set/Cargo.toml b/language/tools/read-write-set/Cargo.toml index fda28ac073..790f684e0a 100644 --- a/language/tools/read-write-set/Cargo.toml +++ b/language/tools/read-write-set/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/read-write-set/dynamic/Cargo.toml b/language/tools/read-write-set/dynamic/Cargo.toml index 1ff84db9dd..206ca47818 100644 --- a/language/tools/read-write-set/dynamic/Cargo.toml +++ b/language/tools/read-write-set/dynamic/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = false -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/language/tools/read-write-set/types/Cargo.toml b/language/tools/read-write-set/types/Cargo.toml index 4ed24a5322..fd2e99385d 100644 --- a/language/tools/read-write-set/types/Cargo.toml +++ b/language/tools/read-write-set/types/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/diem/diem" homepage = "https://diem.com" license = "Apache-2.0" publish = ["crates-io"] -edition = "2018" +edition = "2021" [dependencies] anyhow = "1.0.52" diff --git a/rust-toolchain b/rust-toolchain index 4d5fde5bd1..b77a81dcb1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.60.0 +1.62.1 diff --git a/rustfmt.toml b/rustfmt.toml index 80eeb4054d..55797efb6b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,2 +1,2 @@ -edition = "2018" +edition = "2021" use_field_init_shorthand = true From 35009fa2d7bd4e1aac8735fb64f0ae9957f9d1f6 Mon Sep 17 00:00:00 2001 From: Ian Macalinao Date: Sat, 30 Jul 2022 14:47:42 -0500 Subject: [PATCH 020/169] [move-analyzer] Improve support for Move doc comments (#255) > Ping on this PR. @awelc is this correctly routed to you? I am sorry I missed it. It's related to VSCode extension which is why it was routed to me I suppose, though my main contributions there are on the language server (Rust) side. Still, it seems like I am now the owner/maintainer here unless @vgao1996 wants to (re)claim the title :-) --- .../move-analyzer/editors/code/src/context.ts | 30 +++++++++++++++++++ .../move-analyzer/editors/code/src/main.ts | 3 ++ 2 files changed, 33 insertions(+) diff --git a/language/move-analyzer/editors/code/src/context.ts b/language/move-analyzer/editors/code/src/context.ts index c962040772..2a5196cc68 100644 --- a/language/move-analyzer/editors/code/src/context.ts +++ b/language/move-analyzer/editors/code/src/context.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { log } from './log'; import { sync as commandExistsSync } from 'command-exists'; +import { IndentAction } from 'vscode'; /** Information passed along to each VS Code command defined by this extension. */ export class Context { @@ -48,6 +49,35 @@ export class Context { this.extensionContext.subscriptions.push(disposable); } + /** + * Sets up additional language configuration that's impossible to do via a + * separate language-configuration.json file. See [1] for more information. + * + * This code originates from [2](vscode-rust). + * + * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076 + * [2]: https://github.com/rust-lang/vscode-rust/blob/660b412701fe2ea62fad180c40ee4f8a60571c61/src/extension.ts#L287:L287 + */ + configureLanguage(): void { + const disposable = vscode.languages.setLanguageConfiguration('move', { + onEnterRules: [ + { + // Doc single-line comment + // e.g. ///| + beforeText: /^\s*\/{3}.*$/, + action: { indentAction: IndentAction.None, appendText: '/// ' }, + }, + { + // Parent doc single-line comment + // e.g. //!| + beforeText: /^\s*\/{2}!.*$/, + action: { indentAction: IndentAction.None, appendText: '//! ' }, + }, + ], + }); + this.extensionContext.subscriptions.push(disposable); + } + /** * Configures and starts the client that interacts with the language server. * diff --git a/language/move-analyzer/editors/code/src/main.ts b/language/move-analyzer/editors/code/src/main.ts index 169bc9b2d1..f2ec1edc8a 100644 --- a/language/move-analyzer/editors/code/src/main.ts +++ b/language/move-analyzer/editors/code/src/main.ts @@ -62,6 +62,9 @@ export function activate(extensionContext: Readonly): v // Register handlers for VS Code commands that the user explicitly issues. context.registerCommand('serverVersion', serverVersion); + // Configure other language features. + context.configureLanguage(); + // All other utilities provided by this extension occur via the language server. context.startClient(); } From a3bccb065bb0972523bd303c162578e0fc9bbc24 Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Mon, 1 Aug 2022 11:06:43 -0400 Subject: [PATCH 021/169] [move-prover][interpreter] two bug fixes to re-enable disabled tests (#324) * [move-prover][interpreter] bug fix for a return_ref test case failure This commit fixes two bugs to re-enable the failing test: - collect pointers for write-backs even when the local slot is destroyed - fix the indexing of the borrow edge in the write-back process. * [move-prover][interpreter] use baseline version for callee with ghost type params This is a temporary solution until we have a better way to multiplex the spec evaluation against multiple universially quantified types. --- .../tests/concrete_check/property/mono.exp | 19 ++++++++++++++++++- .../tests/concrete_check/property/mono.move | 11 ++++------- .../tests/concrete_check/return_mut_ref.exp | 3 ++- .../tests/concrete_check/return_mut_ref.move | 3 +-- .../interpreter/src/concrete/local_state.rs | 5 +++++ .../interpreter/src/concrete/player.rs | 2 +- .../interpreter/src/shared/variant.rs | 5 ++++- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.exp index be28cc6e9c..29c4eb99a6 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.exp +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.exp @@ -1,2 +1,19 @@ Running Move unit tests -Test result: OK. Total tests: 0; passed: 0; failed: 0 +[ FAIL ] 0x2::Test::check_0x1_fail +[ PASS ] 0x2::Test::check_0x2_pass + +Test failures: + +Failures in 0x2::Test: + +┌── check_0x1_fail ────── +│ error: property does not hold +│ ┌─ tests/concrete_check/property/mono.move:50:13 +│ │ +│ 50 │ (Base::has_b() && has_r()) ==> old(has_r()); +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ +│ +└────────────────── + +Test result: FAILED. Total tests: 2; passed: 1; failed: 1 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.move index 4352b2610b..a8fe2d3bd4 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/property/mono.move @@ -29,14 +29,12 @@ module Test { move_to(s, R { f: v }); } - // TODO (mengxu), after mono, the global invariant is changed to Base::has_b() ==> true... - // #[test(s=@0x2)] + #[test(s=@0x2)] public fun check_0x2_pass(s: &signer) { put_r(s, true); } - // TODO (mengxu), after mono, the global invariant is changed to Base::has_b() ==> true... - // #[test(s=@0x1)] + #[test(s=@0x1)] public fun check_0x1_fail(s: &signer) { put_r(s, true); } @@ -48,9 +46,8 @@ module Test { } spec module { - invariant update - Base::has_b() ==> - (forall t: type where has_r(): old(has_r())); + invariant update + (Base::has_b() && has_r()) ==> old(has_r()); } } } diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.exp index 0a71d9a67c..6fe1a05174 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.exp +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.exp @@ -1,4 +1,5 @@ Running Move unit tests [ PASS ] 0x2::A::return_ref_path +[ PASS ] 0x2::A::return_ref_path_vec_1 [ PASS ] 0x2::A::return_ref_root -Test result: OK. Total tests: 2; passed: 2; failed: 0 +Test result: OK. Total tests: 3; passed: 3; failed: 0 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.move index b2bcdb3b01..93d1d22d63 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/return_mut_ref.move @@ -47,8 +47,7 @@ module 0x2::A { } } - // TODO there is a bug in spec_instrumenter that produces wrong goto labels: - // #[test] + #[test] public fun return_ref_path_vec_1(): V { let is = vector::empty(); let ts = vector::empty(); diff --git a/language/move-prover/interpreter/src/concrete/local_state.rs b/language/move-prover/interpreter/src/concrete/local_state.rs index b2ef58a077..efb21fa360 100644 --- a/language/move-prover/interpreter/src/concrete/local_state.rs +++ b/language/move-prover/interpreter/src/concrete/local_state.rs @@ -170,6 +170,11 @@ impl LocalState { .iter() .enumerate() .filter_map(|(idx, slot)| slot.get_content().map(|(_, ptr)| (idx, ptr))) + .chain( + self.destroyed_args + .iter() + .map(|(idx, val)| (*idx, val.get_ptr())), + ) .collect() } diff --git a/language/move-prover/interpreter/src/concrete/player.rs b/language/move-prover/interpreter/src/concrete/player.rs index 10fe4d9afc..7311f2a021 100644 --- a/language/move-prover/interpreter/src/concrete/player.rs +++ b/language/move-prover/interpreter/src/concrete/player.rs @@ -1448,7 +1448,7 @@ impl<'env> FunctionContext<'env> { // TODO (mengxu): refactor the code to remove this clone let mut cur = op_val.clone(); for (i, (val, edge)) in path.into_iter().zip(edges.iter()).rev().enumerate() { - let ptr = trace.get(steps - 1 - i).unwrap(); + let ptr = trace.get(i).unwrap(); let sub = match edge { BorrowEdge::Field(_, field_num) => { val.update_ref_struct_field(*field_num, cur) diff --git a/language/move-prover/interpreter/src/shared/variant.rs b/language/move-prover/interpreter/src/shared/variant.rs index 35bc7606d8..8acb49d05a 100644 --- a/language/move-prover/interpreter/src/shared/variant.rs +++ b/language/move-prover/interpreter/src/shared/variant.rs @@ -23,7 +23,10 @@ pub fn choose_variant<'env>( } } FunctionVariant::Verification(VerificationFlavor::Regular) => { - target_variant = Some(target); + // TODO (mengxu): think about a way to handle ghost type parameters + if target.data.ghost_type_param_count == 0 { + target_variant = Some(target); + } } _ => (), } From 2e4a18480c0c3a0416d50c773e3470f01303740d Mon Sep 17 00:00:00 2001 From: Ville Sundell Date: Mon, 1 Aug 2022 20:32:51 +0300 Subject: [PATCH 022/169] [Move analyzer] Updated package info & clap usage (#279) While "move-analyzer --version" reports "1.0.0", the package itself is at version 0.0.0. This is because version information is hardcoded to the clap() usage, and the Cargo.toml package manifest is out-of-date. Updated Cargo.toml information: dropping the Diem repo and setting a proper version. Clap() usage was also changed to idiomatic one as per 9225b84aa ("Idiomatic "clap" usage (implements --version switch for tools) (#81)", 2022-05-02) --- Cargo.lock | 2 +- language/move-analyzer/Cargo.toml | 5 ++--- language/move-analyzer/src/bin/move-analyzer.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58a0a0a47d..a47f5abb50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2286,7 +2286,7 @@ dependencies = [ [[package]] name = "move-analyzer" -version = "0.0.0" +version = "1.0.0" dependencies = [ "anyhow", "clap 3.1.8", diff --git a/language/move-analyzer/Cargo.toml b/language/move-analyzer/Cargo.toml index ea1ca98156..e9ce8d64ba 100644 --- a/language/move-analyzer/Cargo.toml +++ b/language/move-analyzer/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "move-analyzer" -version = "0.0.0" +version = "1.0.0" authors = ["Diem Association "] description = "A language server for Move" -repository = "https://github.com/diem/diem" -homepage = "https://diem.com" +repository = "https://github.com/move-language/move" license = "Apache-2.0" publish = false edition = "2021" diff --git a/language/move-analyzer/src/bin/move-analyzer.rs b/language/move-analyzer/src/bin/move-analyzer.rs index 779c8c4c6e..9d2b0f39bc 100644 --- a/language/move-analyzer/src/bin/move-analyzer.rs +++ b/language/move-analyzer/src/bin/move-analyzer.rs @@ -28,7 +28,7 @@ use move_symbol_pool::Symbol; use url::Url; #[derive(Parser)] -#[clap(author, version = "1.0.0", about)] +#[clap(author, version, about)] struct Options {} fn main() { From 115c4fb59070a949b28867bce0b722c830d2ac72 Mon Sep 17 00:00:00 2001 From: Junkil Park Date: Mon, 1 Aug 2022 12:06:41 -0700 Subject: [PATCH 023/169] Bump up the version number of the Prover dependencies (#309) - Updated the Z3 version to the latest one. - Updated the Boogie version to latest one that is compatible with Prover. - Fixed a few bugs in `boogie_wrapper`. --- .../boogie-backend/src/boogie_wrapper.rs | 2 +- .../move-prover/boogie-backend/src/options.rs | 7 +++++-- .../sources/functional/loops_with_memory_ops.exp | 15 +++++++-------- scripts/dev_setup.sh | 10 +++++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/language/move-prover/boogie-backend/src/boogie_wrapper.rs b/language/move-prover/boogie-backend/src/boogie_wrapper.rs index 6064366124..bae2e32eb1 100644 --- a/language/move-prover/boogie-backend/src/boogie_wrapper.rs +++ b/language/move-prover/boogie-backend/src/boogie_wrapper.rs @@ -1682,7 +1682,7 @@ impl<'s> ModelParser<'s> { fn parse_key(&mut self) -> Result { let mut comps = vec![]; - while !self.looking_at("->") { + while !self.looking_at("->") && self.at < self.input.len() { let value = self.parse_value()?; comps.push(value); } diff --git a/language/move-prover/boogie-backend/src/options.rs b/language/move-prover/boogie-backend/src/options.rs index fb87fe9cbe..fe7f446be1 100644 --- a/language/move-prover/boogie-backend/src/options.rs +++ b/language/move-prover/boogie-backend/src/options.rs @@ -19,8 +19,8 @@ const DEFAULT_BOOGIE_FLAGS: &[&str] = &[ "-proverOpt:O:model_validate=true", ]; -const MIN_BOOGIE_VERSION: &str = "2.9.0"; -const MIN_Z3_VERSION: &str = "4.8.9"; +const MIN_BOOGIE_VERSION: &str = "2.13.4"; +const MIN_Z3_VERSION: &str = "4.10.2"; const MIN_CVC5_VERSION: &str = "0.0.3"; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] @@ -320,6 +320,9 @@ impl BoogieOptions { tool )); } + if gn > en { + break; + } } Ok(()) } diff --git a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp index b22828139c..619c465f35 100644 --- a/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp +++ b/language/move-prover/tests/sources/functional/loops_with_memory_ops.exp @@ -45,9 +45,11 @@ error: unknown assertion failed = y = = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = - = b = - = a = + = at :1 + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = a = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = @@ -100,13 +102,10 @@ error: induction case of the loop invariant does not hold = y = = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = b = + = b = + = a = = a = - = at :1 - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 diff --git a/scripts/dev_setup.sh b/scripts/dev_setup.sh index b4c225e5ff..a228e993f5 100755 --- a/scripts/dev_setup.sh +++ b/scripts/dev_setup.sh @@ -15,10 +15,10 @@ # fast fail. set -eo pipefail -Z3_VERSION=4.8.13 +Z3_VERSION=4.10.2 CVC5_VERSION=0.0.3 -DOTNET_VERSION=5.0 -BOOGIE_VERSION=2.9.6 +DOTNET_VERSION=6.0 +BOOGIE_VERSION=2.13.4 SOLC_VERSION="v0.8.11+commit.d7f03943" SCRIPT_PATH="$(cd "$(dirname "$0")" >/dev/null 2>&1 && pwd)" @@ -294,7 +294,7 @@ function install_z3 { return fi if [[ "$(uname)" == "Linux" ]]; then - Z3_PKG="z3-$Z3_VERSION-x64-glibc-2.28" + Z3_PKG="z3-$Z3_VERSION-x64-glibc-2.31" elif [[ "$(uname)" == "Darwin" ]]; then Z3_PKG="z3-$Z3_VERSION-x64-osx-10.16" else @@ -306,7 +306,7 @@ function install_z3 { mkdir -p "$TMPFILE"/ ( cd "$TMPFILE" || exit - curl -LOs "https://github.com/junkil-park/z3/releases/download/z3-$Z3_VERSION/$Z3_PKG.zip" + curl -LOs "https://github.com/Z3Prover/z3/releases/download/z3-$Z3_VERSION/$Z3_PKG.zip" unzip -q "$Z3_PKG.zip" cp "$Z3_PKG/bin/z3" "${INSTALL_DIR}" chmod +x "${INSTALL_DIR}z3" From 01e535ec6956e52173d8b4130588847f76191451 Mon Sep 17 00:00:00 2001 From: Emma Zhong Date: Fri, 29 Jul 2022 14:02:47 -0700 Subject: [PATCH 024/169] make instruction execution bound an option and increment default value --- .../tests/concrete_check_testsuite.rs | 2 +- language/tools/move-cli/src/base/test.rs | 9 ++------- language/tools/move-unit-test/src/lib.rs | 17 ++++++++--------- .../tests/move_unit_test_testsuite.rs | 2 +- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check_testsuite.rs b/language/move-prover/interpreter-testsuite/tests/concrete_check_testsuite.rs index 5ff9d9d4bf..5070701546 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check_testsuite.rs +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check_testsuite.rs @@ -14,7 +14,7 @@ fn test_runner(path: &Path) -> datatest_stable::Result<()> { let source_files = vec![path.to_str().unwrap().to_owned()]; let config = UnitTestingConfig { - instruction_execution_bound: 5000, + instruction_execution_bound: Some(5000), num_threads: 1, source_files, dep_files: move_stdlib_files(), diff --git a/language/tools/move-cli/src/base/test.rs b/language/tools/move-cli/src/base/test.rs index f5e4a48ee1..e8bd2f8009 100644 --- a/language/tools/move-cli/src/base/test.rs +++ b/language/tools/move-cli/src/base/test.rs @@ -37,13 +37,8 @@ compile_error!("Unsupported OS, currently we only support windows and unix famil #[clap(name = "test")] pub struct Test { /// Bound the number of instructions that can be executed by any one test. - #[clap( - name = "instructions", - default_value = "5000", - short = 'i', - long = "instructions" - )] - pub instruction_execution_bound: u64, + #[clap(name = "instructions", short = 'i', long = "instructions")] + pub instruction_execution_bound: Option, /// A filter string to determine which unit tests to run. A unit test will be run only if it /// contains this string in its fully qualified (::::) name. #[clap(name = "filter", short = 'f', long = "filter")] diff --git a/language/tools/move-unit-test/src/lib.rs b/language/tools/move-unit-test/src/lib.rs index 1a5453a404..c3fb91736d 100644 --- a/language/tools/move-unit-test/src/lib.rs +++ b/language/tools/move-unit-test/src/lib.rs @@ -26,17 +26,15 @@ use std::{ sync::Mutex, }; +/// The default value bounding the number of instructions executed in a test. +const DEFAULT_EXECUTION_BOUND: u64 = 100_000; + #[derive(Debug, Parser, Clone)] #[clap(author, version, about)] pub struct UnitTestingConfig { /// Bound the number of instructions that can be executed by any one test. - #[clap( - name = "instructions", - default_value = "5000", - short = 'i', - long = "instructions" - )] - pub instruction_execution_bound: u64, + #[clap(name = "instructions", short = 'i', long = "instructions")] + pub instruction_execution_bound: Option, /// A filter string to determine which unit tests to run #[clap(name = "filter", short = 'f', long = "filter")] @@ -127,7 +125,7 @@ impl UnitTestingConfig { /// Create a unit testing config for use with `register_move_unit_tests` pub fn default_with_bound(bound: Option) -> Self { Self { - instruction_execution_bound: bound.unwrap_or(5000), + instruction_execution_bound: bound.or(Some(DEFAULT_EXECUTION_BOUND)), filter: None, num_threads: 8, report_statistics: false, @@ -225,7 +223,8 @@ impl UnitTestingConfig { writeln!(shared_writer.lock().unwrap(), "Running Move unit tests")?; let mut test_runner = TestRunner::new( - self.instruction_execution_bound, + self.instruction_execution_bound + .unwrap_or(DEFAULT_EXECUTION_BOUND), self.num_threads, self.check_stackless_vm, self.verbose, diff --git a/language/tools/move-unit-test/tests/move_unit_test_testsuite.rs b/language/tools/move-unit-test/tests/move_unit_test_testsuite.rs index 43c68624c9..e0e375d424 100644 --- a/language/tools/move-unit-test/tests/move_unit_test_testsuite.rs +++ b/language/tools/move-unit-test/tests/move_unit_test_testsuite.rs @@ -82,7 +82,7 @@ fn run_test_impl(path: &Path) -> anyhow::Result<()> { let source_files = vec![path.to_str().unwrap().to_owned()]; let unit_test_config = UnitTestingConfig { num_threads: 1, - instruction_execution_bound: 1000, + instruction_execution_bound: Some(1000), source_files, dep_files: move_stdlib::move_stdlib_files(), named_address_values: move_stdlib::move_stdlib_named_addresses() From fdcd02172a5c87a07291445d7dbf7ba4a0254a52 Mon Sep 17 00:00:00 2001 From: Owen Wu <1449069+yubing744@users.noreply.github.com> Date: Tue, 2 Aug 2022 07:56:54 +0800 Subject: [PATCH 025/169] [move-analyzer] Support document symbol PSL (#218) * feat: add release workflow * feat: update release script * feat: update release * feat: fmt release.sh * feat: add lsp.test.ts for move-analyzer * feat: fix copyfiles error * feat: config test for lsp * feat: ok for lsp test * feat: get symbols from table * feat: export symbols * feat: test textDocument/documentSymbol * feat: re impl symbols * feat: parse symbols tree * feat: ok for on_document_symbol_request * feat: auto build move-analyzer and set default for serverPath * feat: fix ci check fail * feat: fix ci check error * feat: fix lint error * fix: fix lsp test fail * feat: fmt move-analyzer code * feat: fix lsp fisrt test error * feat: update timeout for move-analyzer active * feat: support events * fix: fix error for LSP test * feat: fix bug for merge from master * feat: fmt code * feat: update test and igonre package-lock.json for broken url test * feat: change name for ready events * feat: remove unrelate code * feat: remove yarn.lock * feat: ignore yarn.lock and recover configuration.ts * feat: update the comment for OnReady * feat: remove codes * feat: lock file * feat: add waiting code * feat: try lock code * feat: test new way * feat: ok for symbols * feat: fix ci-check issue * feat: update ci-check issues * feat: fix ci-check issues * [Move analyzer] Added support for computing first symbol info synchronously * feat: handle symbols on start * feat: remove unuse code * feat: format code * feat: add test for mac and windows platform * feat: fix bug for uri to path * feat: fixbug for windows platform get_symbols stack overflow * feat: fixbug for reporting lsp diagnostics * feat: fixbug for windows test * feat: fix lint error for language/move-analyzer/src/symbols.rs * feat: remove config for windows stack * feat: update pipeline for move-analyzer * feat: change name for test-move-analyzer-vscode-extension * feat: remove tsfmt for windows check fail * feat: fixbug for stack overflow and lint error * feat: fix lint error * feat: add commit for linebreak-style * feat: fix code review issue * feat: remove linkarg config * feat: update cargo/config fmt * feat: config move-analyzer test vscode version to 1.69.2 * feat: add comments for plugin activate * feat: upgrate ci-test mac system to mac-11 * feat: update style issue * feat: fixbug for user data dir too long for 1.69.2 * feat: fixbug for userDataDir too long * feat: fixbug for vsce package missing files * feat: add feature in README.md * feat: add comment for startClient func in context.ts * feat: update package-lock.json * feat: format context.ts * feat: update package-lock.json for move-analyzer * feat: format context.ts * feat: add outline feature detail descripe * feat: format README Co-authored-by: Adam Welc --- .github/workflows/ci-pre-land.yml | 34 +- Cargo.lock | 1 + language/move-analyzer/Cargo.toml | 1 + .../move-analyzer/editors/code/.eslintrc.json | 15 +- .../move-analyzer/editors/code/.gitignore | 2 + .../move-analyzer/editors/code/.vscodeignore | 2 +- language/move-analyzer/editors/code/README.md | 1 + .../editors/code/package-lock.json | 14503 ++++++++-------- .../move-analyzer/editors/code/package.json | 26 +- .../editors/code/src/commands/index.ts | 1 + .../editors/code/src/commands/lsp_command.ts | 24 + .../editors/code/src/configuration.ts | 23 +- .../move-analyzer/editors/code/src/context.ts | 42 +- .../move-analyzer/editors/code/src/main.ts | 11 +- .../move-analyzer/editors/code/tests/index.ts | 10 +- .../editors/code/tests/lsp-demo/Move.toml | 9 + .../lsp-demo/lsp-demo-win.code-workspace | 10 + .../tests/lsp-demo/lsp-demo.code-workspace | 10 + .../code/tests/lsp-demo/sources/M1.move | 18 + .../editors/code/tests/lsp.test.ts | 52 + .../editors/code/tests/runTests.ts | 47 +- .../code/types/vscode-test-electron.d.ts | 14 - .../move-analyzer/src/bin/move-analyzer.rs | 4 + language/move-analyzer/src/symbols.rs | 246 +- 24 files changed, 7979 insertions(+), 7127 deletions(-) create mode 100644 language/move-analyzer/editors/code/src/commands/index.ts create mode 100644 language/move-analyzer/editors/code/src/commands/lsp_command.ts create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/Move.toml create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move create mode 100644 language/move-analyzer/editors/code/tests/lsp.test.ts delete mode 100644 language/move-analyzer/editors/code/types/vscode-test-electron.d.ts diff --git a/.github/workflows/ci-pre-land.yml b/.github/workflows/ci-pre-land.yml index 9b2435563d..634dd8b0cc 100644 --- a/.github/workflows/ci-pre-land.yml +++ b/.github/workflows/ci-pre-land.yml @@ -205,13 +205,19 @@ jobs: # path: | # /tmp/benches - build-move-analyzer-vscode-extension: - name: Build VS Code extension for move-analyzer - runs-on: ubuntu-latest + test-move-analyzer-vscode-extension: + name: Test VS Code extension for move-analyzer + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, macos-11, windows-2022] + runs-on: ${{ matrix.os }} needs: - prepare steps: - uses: actions/checkout@v2.4.0 + - name: install rust toolchain + uses: actions-rs/toolchain@v1 - name: Use Node.js 14 uses: actions/setup-node@v2.4.0 with: @@ -232,6 +238,26 @@ jobs: with: working-directory: language/move-analyzer/editors/code run: npm run test + + release-move-analyzer-vscode-extension: + name: Release VS Code extension for move-analyzer + runs-on: ubuntu-20.04 + needs: + - prepare + steps: + - uses: actions/checkout@v2.4.0 + - name: install rust toolchain + uses: actions-rs/toolchain@v1 + - name: Use Node.js 14 + uses: actions/setup-node@v2.4.0 + with: + node-version: "14" + - name: Install NPM dependencies + working-directory: language/move-analyzer/editors/code + run: npm install + - name: Build the extension + working-directory: language/move-analyzer/editors/code + run: npm run pretest - name: Package the extension working-directory: language/move-analyzer/editors/code run: npm run package @@ -257,7 +283,7 @@ jobs: gem install awesome_bot # Don't look in git or target dirs. Don't check png, bib, tex, js, or shell files # We allow links to be redirects, allow duplicates, and we also allow Too Many Requests (429) errors - find . -not \( -path "./.git*" -prune \) -not \( -path "./target" -prune \) -type f -not -name "*.png" -not -name "*.sh" -not -name "*.bib" -not -name "*.tex" -not -name "*.js" | while read arg; do awesome_bot --allow-redirect --allow-dupe --allow 429 --skip-save-results $arg; done + find . -not \( -path "./.git*" -prune \) -not \( -path "./target" -prune \) -type f -not -name "*.png" -not -name "*.sh" -not -name "*.bib" -not -name "*.tex" -not -name "*.js" -not -name "package-lock.json" | while read arg; do awesome_bot --allow-redirect --allow-dupe --allow 429 --skip-save-results $arg; done build-move-cli-docker-image: name: Build Docker image for the Move CLI diff --git a/Cargo.lock b/Cargo.lock index a47f5abb50..4820df75ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2302,6 +2302,7 @@ dependencies = [ "move-package", "move-symbol-pool", "petgraph 0.5.1", + "serde 1.0.130", "serde_json", "tempfile", "url", diff --git a/language/move-analyzer/Cargo.toml b/language/move-analyzer/Cargo.toml index e9ce8d64ba..a8f2d2a787 100644 --- a/language/move-analyzer/Cargo.toml +++ b/language/move-analyzer/Cargo.toml @@ -16,6 +16,7 @@ im = "15.1.0" lsp-server = "0.5.1" lsp-types = "0.90.1" petgraph = "0.5.1" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.64" tempfile = "3.2.0" url = "2.2.2" diff --git a/language/move-analyzer/editors/code/.eslintrc.json b/language/move-analyzer/editors/code/.eslintrc.json index 084af02eea..2238dc578b 100644 --- a/language/move-analyzer/editors/code/.eslintrc.json +++ b/language/move-analyzer/editors/code/.eslintrc.json @@ -106,7 +106,7 @@ "function-call-argument-newline": ["warn", "consistent"], "function-paren-newline": ["warn", "consistent"], "key-spacing": "warn", - "linebreak-style": "warn", + "linebreak-style": "off", // We use different linebreak styles. ref https://eslint.org/docs/latest/rules/linebreak-style "max-len": [ "warn", { @@ -139,7 +139,6 @@ // * All @typescript-eslint rules: https://github.com/typescript-eslint/typescript-eslint/tree/v4.31.1/packages/eslint-plugin/docs/rules // * The rules included in @typescript-eslint/recommended: https://github.com/typescript-eslint/typescript-eslint/blob/v4.31.1/packages/eslint-plugin/src/configs/recommended.ts // * The rules included in @typescript-eslint/recommended-requiring-type-checking: https://github.com/typescript-eslint/typescript-eslint/blob/v4.31.1/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts - "@typescript-eslint/array-type": ["warn", { "default": "generic" }], "@typescript-eslint/ban-tslint-comment": "warn", "@typescript-eslint/brace-style": "warn", "@typescript-eslint/comma-dangle": [ @@ -158,7 +157,7 @@ "@typescript-eslint/keyword-spacing": "warn", "@typescript-eslint/lines-between-class-members": "warn", "@typescript-eslint/member-delimiter-style": "warn", - "@typescript-eslint/naming-convention": "warn", + "@typescript-eslint/naming-convention": "off", "@typescript-eslint/no-base-to-string": "warn", "@typescript-eslint/no-confusing-non-null-assertion": "warn", "@typescript-eslint/no-duplicate-imports": "warn", @@ -206,10 +205,16 @@ ], "@typescript-eslint/strict-boolean-expressions": "warn", "@typescript-eslint/switch-exhaustiveness-check": "warn", - "@typescript-eslint/type-annotation-spacing": "warn", "@typescript-eslint/unified-signatures": "warn", // The following are eslint-plugin-tsdoc rules: - "tsdoc/syntax": "warn" + "tsdoc/syntax": "warn", + + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/type-annotation-spacing": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/array-type": "off" } } diff --git a/language/move-analyzer/editors/code/.gitignore b/language/move-analyzer/editors/code/.gitignore index 036b79d9db..8174e373d7 100644 --- a/language/move-analyzer/editors/code/.gitignore +++ b/language/move-analyzer/editors/code/.gitignore @@ -7,3 +7,5 @@ out .vscode-test # VS Code extension package (VSIX) archive *.vsix +# Yarn cache directory +yarn.lock diff --git a/language/move-analyzer/editors/code/.vscodeignore b/language/move-analyzer/editors/code/.vscodeignore index c170fc4dee..ddd5d59296 100644 --- a/language/move-analyzer/editors/code/.vscodeignore +++ b/language/move-analyzer/editors/code/.vscodeignore @@ -5,7 +5,7 @@ **/* !images/move.png -!out/src/* +!out/src/**/* !node_modules/**/* !language-configuration.json !move.tmLanguage.json diff --git a/language/move-analyzer/editors/code/README.md b/language/move-analyzer/editors/code/README.md index a43c1c434b..196e36dece 100644 --- a/language/move-analyzer/editors/code/README.md +++ b/language/move-analyzer/editors/code/README.md @@ -86,3 +86,4 @@ Move source file (a file with a `.move` file extension) and: - go to type definition - go to references - type on hover + - outline view showing symbol tree for Move source files diff --git a/language/move-analyzer/editors/code/package-lock.json b/language/move-analyzer/editors/code/package-lock.json index 7be9879524..b4126498af 100644 --- a/language/move-analyzer/editors/code/package-lock.json +++ b/language/move-analyzer/editors/code/package-lock.json @@ -1,7063 +1,7444 @@ { - "name": "move-analyzer", - "version": "0.0.7", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "move-analyzer", - "version": "0.0.7", - "license": "Apache-2.0", - "dependencies": { - "command-exists": "^1.2.9", - "vscode-languageclient": "6.1.4" - }, - "devDependencies": { - "@types/command-exists": "^1.2.0", - "@types/glob": "^7.1.4", - "@types/mocha": "^9.0.0", - "@types/node": "^14.17.22", - "@types/vscode": "^1.58.2", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "@vscode/test-electron": "^1.6.1", - "eslint": "^7.32.0", - "eslint-plugin-tsdoc": "^0.2.14", - "glob": "^7.1.7", - "mocha": "^9.1.1", - "typescript": "^4.4.4", - "typescript-formatter": "^7.2.2", - "vsce": "^2.5.1", - "vscode-test": "^1.6.1" - }, - "engines": { - "vscode": "^1.58.2" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", - "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", - "dev": true - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", - "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.13.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/command-exists": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", - "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/mocha": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", - "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", - "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", - "dev": true - }, - "node_modules/@types/vscode": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", - "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/@vscode/test-electron": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-1.6.2.tgz", - "integrity": "sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/azure-devops-node-api": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", - "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", - "dev": true, - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true, - "engines": { - "node": ">=0.2.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cheerio/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-tsdoc": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", - "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.13.2", - "@microsoft/tsdoc-config": "0.15.2" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/keytar": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", - "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^3.0.0", - "prebuild-install": "^6.0.0" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "dependencies": { - "semver": "^5.4.1" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "dependencies": { - "semver": "^5.1.0" - } - }, - "node_modules/parse-semver/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dev": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-rest-client": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", - "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", - "dev": true, - "dependencies": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "dependencies": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - }, - "bin": { - "tsfmt": "bin/tsfmt" - }, - "engines": { - "node": ">= 4.2.0" - }, - "peerDependencies": { - "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "node_modules/unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/vsce": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", - "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", - "dev": true, - "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/vsce/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/vsce/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/vsce/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/vsce/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/vscode-jsonrpc": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", - "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==", - "engines": { - "node": ">=8.0.0 || >=10.0.0" - } - }, - "node_modules/vscode-languageclient": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", - "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", - "dependencies": { - "semver": "^6.3.0", - "vscode-languageserver-protocol": "3.15.3" - }, - "engines": { - "vscode": "^1.41.0" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", - "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", - "dependencies": { - "vscode-jsonrpc": "^5.0.1", - "vscode-languageserver-types": "3.15.1" - } - }, - "node_modules/vscode-languageserver-types": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", - "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" - }, - "node_modules/vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "@microsoft/tsdoc": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", - "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", - "dev": true - }, - "@microsoft/tsdoc-config": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", - "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.13.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/command-exists": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", - "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", - "dev": true - }, - "@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "@types/mocha": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", - "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", - "dev": true - }, - "@types/node": { - "version": "14.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", - "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", - "dev": true - }, - "@types/vscode": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", - "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - } - }, - "@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "@vscode/test-electron": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-1.6.2.tgz", - "integrity": "sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "azure-devops-node-api": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", - "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-tsdoc": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", - "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.13.2", - "@microsoft/tsdoc-config": "0.15.2" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "keytar": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", - "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", - "dev": true, - "requires": { - "node-addon-api": "^3.0.0", - "prebuild-install": "^6.0.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "requires": { - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "requires": { - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true - }, - "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dev": true, - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-rest-client": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", - "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true - }, - "typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "requires": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - } - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "vsce": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", - "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "vscode-jsonrpc": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", - "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==" - }, - "vscode-languageclient": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", - "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", - "requires": { - "semver": "^6.3.0", - "vscode-languageserver-protocol": "3.15.3" - } - }, - "vscode-languageserver-protocol": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", - "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", - "requires": { - "vscode-jsonrpc": "^5.0.1", - "vscode-languageserver-types": "3.15.1" - } - }, - "vscode-languageserver-types": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", - "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" - }, - "vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } + "name": "move-analyzer", + "version": "0.0.10", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "move-analyzer", + "version": "0.0.10", + "license": "Apache-2.0", + "dependencies": { + "command-exists": "^1.2.9", + "lru-cache": "^4.1.3", + "vscode-languageclient": "6.1.4" + }, + "devDependencies": { + "@types/command-exists": "^1.2.0", + "@types/fs-extra": "^9.0.13", + "@types/glob": "^7.1.4", + "@types/mocha": "^9.0.0", + "@types/node": "^14.17.22", + "@types/vscode": "^1.58.2", + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", + "@vscode/test-electron": "^2.0.0", + "copyfiles": "2.4.1", + "cross-env": "^7.0.3", + "eslint": "^7.32.0", + "eslint-plugin-tsdoc": "^0.2.14", + "fs-extra": "10.0.1", + "glob": "^7.1.7", + "mocha": "^9.1.1", + "typescript": "^4.4.4", + "typescript-formatter": "^7.2.2", + "vsce": "^2.5.1", + "vscode-test": "^1.6.1" + }, + "engines": { + "vscode": "^1.58.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", + "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", + "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.13.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/command-exists": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", + "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", + "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.17.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", + "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", + "dev": true + }, + "node_modules/@types/vscode": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", + "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", + "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.33.0", + "@typescript-eslint/scope-manager": "4.33.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", + "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", + "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", + "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", + "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", + "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", + "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/@vscode/test-electron": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", + "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/azure-devops-node-api": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", + "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", + "dev": true, + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big-integer": { + "version": "1.6.50", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", + "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dev": true, + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cheerio/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "node_modules/copyfiles/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", + "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.13.2", + "@microsoft/tsdoc-config": "0.15.2" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keytar": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", + "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^3.0.0", + "prebuild-install": "^6.0.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "dev": true, + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true + }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/noms/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/noms/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/noms/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", + "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", + "dev": true, + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", + "dev": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.21.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", + "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "node_modules/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dev": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", + "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", + "dev": true, + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", + "dev": true, + "dependencies": { + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" + }, + "bin": { + "tsfmt": "bin/tsfmt" + }, + "engines": { + "node": ">= 4.2.0" + }, + "peerDependencies": { + "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vsce": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", + "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^10.0.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/vsce/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", + "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==", + "engines": { + "node": ">=8.0.0 || >=10.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", + "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", + "dependencies": { + "semver": "^6.3.0", + "vscode-languageserver-protocol": "3.15.3" + }, + "engines": { + "vscode": "^1.41.0" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", + "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", + "dependencies": { + "vscode-jsonrpc": "^5.0.1", + "vscode-languageserver-types": "3.15.1" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", + "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" + }, + "node_modules/vscode-test": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", + "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", + "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@microsoft/tsdoc": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", + "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", + "dev": true + }, + "@microsoft/tsdoc-config": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", + "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.13.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/command-exists": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", + "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", + "dev": true + }, + "@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/mocha": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", + "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", + "dev": true + }, + "@types/node": { + "version": "14.17.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", + "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", + "dev": true + }, + "@types/vscode": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", + "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", + "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.33.0", + "@typescript-eslint/scope-manager": "4.33.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", + "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", + "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", + "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0" + } + }, + "@typescript-eslint/types": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", + "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", + "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", + "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.33.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "@vscode/test-electron": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", + "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "dev": true, + "requires": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "azure-devops-node-api": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", + "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", + "dev": true, + "requires": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "big-integer": { + "version": "1.6.50", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", + "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dev": true, + "requires": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + } + } + }, + "cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "requires": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + } + }, + "css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, + "domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-plugin-tsdoc": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", + "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.13.2", + "@microsoft/tsdoc-config": "0.15.2" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keytar": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", + "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", + "dev": true, + "requires": { + "node-addon-api": "^3.0.0", + "prebuild-install": "^6.0.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "dev": true, + "requires": { + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true + }, + "noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-inspect": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", + "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", + "dev": true, + "requires": { + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "prebuild-install": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.21.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", + "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dev": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-rest-client": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", + "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", + "dev": true, + "requires": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "dev": true + }, + "typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", + "dev": true, + "requires": { + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vsce": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", + "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^10.0.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "vscode-jsonrpc": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", + "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==" + }, + "vscode-languageclient": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", + "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", + "requires": { + "semver": "^6.3.0", + "vscode-languageserver-protocol": "3.15.3" + } + }, + "vscode-languageserver-protocol": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", + "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", + "requires": { + "vscode-jsonrpc": "^5.0.1", + "vscode-languageserver-types": "3.15.1" + } + }, + "vscode-languageserver-types": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", + "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" + }, + "vscode-test": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", + "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", + "dev": true, + "requires": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } } diff --git a/language/move-analyzer/editors/code/package.json b/language/move-analyzer/editors/code/package.json index c9008c3d7e..9e54615e57 100644 --- a/language/move-analyzer/editors/code/package.json +++ b/language/move-analyzer/editors/code/package.json @@ -5,7 +5,7 @@ "publisher": "move", "icon": "images/move.png", "license": "Apache-2.0", - "version": "0.0.9", + "version": "0.0.10", "preview": true, "homepage": "https://github.com/move-language/move", "repository": { @@ -26,7 +26,8 @@ ], "main": "./out/src/main.js", "activationEvents": [ - "onLanguage:move" + "onLanguage:move", + "workspaceContains:Move.toml" ], "contributes": { "commands": [ @@ -85,14 +86,16 @@ } }, "scripts": { - "compile": "tsc -p ./", + "compile": "tsc -p ./ && cd ../../ && cargo build", "watch": "tsc -watch -p ./", - "lint": "tsfmt --verify && eslint . --ext ts --max-warnings 0", - "fix": "tsfmt --replace && eslint . --ext ts --fix", - "pretest": "npm run compile && npm run lint", + "lint": "eslint . --ext ts --max-warnings 0", + "fix": "eslint . --ext ts --fix", + "copy-tests-files": "copyfiles \"tests/**/*.move\" \"tests/**/*.exp\" \"tests/**/*.toml\" \"tests/**/*.code-workspace\" out", + "pretest": "npm run compile && npm run lint && npm run copy-tests-files", "test": "node ./out/tests/runTests.js", + "dev": "npm run pretest && cross-env mode=dev node ./out/tests/runTests.js", "vscode:prepublish": "npm run pretest", - "package": "vsce package -o move-analyzer.vsix", + "package": "npm run pretest && vsce package -o move-analyzer.vsix", "publish": "npm run pretest && npm run test && vsce publish" }, "extensionDependencies": [ @@ -100,19 +103,24 @@ ], "dependencies": { "command-exists": "^1.2.9", - "vscode-languageclient": "6.1.4" + "vscode-languageclient": "6.1.4", + "lru-cache": "^4.1.3" }, "devDependencies": { "@types/command-exists": "^1.2.0", + "@types/fs-extra": "^9.0.13", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "^14.17.22", "@types/vscode": "^1.58.2", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", - "@vscode/test-electron": "^1.6.1", + "@vscode/test-electron": "^2.0.0", + "copyfiles": "2.4.1", + "cross-env": "^7.0.3", "eslint": "^7.32.0", "eslint-plugin-tsdoc": "^0.2.14", + "fs-extra": "10.0.1", "glob": "^7.1.7", "mocha": "^9.1.1", "typescript": "^4.4.4", diff --git a/language/move-analyzer/editors/code/src/commands/index.ts b/language/move-analyzer/editors/code/src/commands/index.ts new file mode 100644 index 0000000000..71d5f7fdfb --- /dev/null +++ b/language/move-analyzer/editors/code/src/commands/index.ts @@ -0,0 +1 @@ +export * from './lsp_command'; diff --git a/language/move-analyzer/editors/code/src/commands/lsp_command.ts b/language/move-analyzer/editors/code/src/commands/lsp_command.ts new file mode 100644 index 0000000000..0387d77d09 --- /dev/null +++ b/language/move-analyzer/editors/code/src/commands/lsp_command.ts @@ -0,0 +1,24 @@ +import type { + DocumentSymbolParams, + SymbolInformation, + DocumentSymbol, +} from 'vscode-languageclient'; +import { DocumentSymbolRequest } from 'vscode-languageclient'; +import type { Context } from '../context'; + +/** + * An LSP command textDocument/documentSymbol + */ +export async function textDocumentDocumentSymbol( + context: Readonly, + params: DocumentSymbolParams, + ) + : Promise { + const client = context.getClient(); + if (client === undefined) { + return Promise.reject(new Error('No language client connected.')); + } + + // Send the request to the language client. + return client.sendRequest(DocumentSymbolRequest.type, params); +} diff --git a/language/move-analyzer/editors/code/src/configuration.ts b/language/move-analyzer/editors/code/src/configuration.ts index 8c37429975..595a791cf5 100644 --- a/language/move-analyzer/editors/code/src/configuration.ts +++ b/language/move-analyzer/editors/code/src/configuration.ts @@ -4,6 +4,7 @@ import * as os from 'os'; import * as vscode from 'vscode'; +import * as Path from 'path'; /** * User-defined configuration values, such as those specified in VS Code settings. @@ -26,16 +27,28 @@ export class Configuration { /** The path to the move-analyzer executable. */ get serverPath(): string { const defaultName = 'move-analyzer'; - const path = this.configuration.get('server.path', defaultName); - if (path.length === 0) { + let serverPath = this.configuration.get('server.path', defaultName); + if (serverPath.length === 0) { // The default value of the `server.path` setting is 'move-analyzer'. // A user may have over-written this default with an empty string value, ''. // An empty string cannot be an executable name, so instead use the default. return defaultName; } - if (path.startsWith('~/')) { - return os.homedir() + path.slice('~'.length); + + if (serverPath === defaultName) { + // If the program set by the user is through PATH, + // it will return directly if specified + return defaultName; + } + + if (serverPath.startsWith('~/')) { + serverPath = os.homedir() + serverPath.slice('~'.length); } - return path; + + if (process.platform === 'win32' && !serverPath.endsWith('.exe')) { + serverPath = serverPath + '.exe'; + } + + return Path.resolve(serverPath); } } diff --git a/language/move-analyzer/editors/code/src/context.ts b/language/move-analyzer/editors/code/src/context.ts index 2a5196cc68..2f894923b8 100644 --- a/language/move-analyzer/editors/code/src/context.ts +++ b/language/move-analyzer/editors/code/src/context.ts @@ -11,10 +11,15 @@ import { IndentAction } from 'vscode'; /** Information passed along to each VS Code command defined by this extension. */ export class Context { + private client: lc.LanguageClient | undefined; + private constructor( private readonly extensionContext: Readonly, readonly configuration: Readonly, - ) { } + client: lc.LanguageClient | undefined = undefined, + ) { + this.client = client; + } static create( extensionContext: Readonly, @@ -40,12 +45,16 @@ export class Context { */ registerCommand( name: Readonly, - command: (context: Readonly) => Promise, + command: (context: Readonly, ...args: Array) => any, ): void { - const disposable = vscode.commands.registerCommand(`move-analyzer.${name}`, async () => { - const com = await command(this); - return com; - }); + const disposable = vscode.commands.registerCommand( + `move-analyzer.${name}`, + async (...args: Array) : Promise => { + const ret = await command(this, ...args); + return ret; + }, + ); + this.extensionContext.subscriptions.push(disposable); } @@ -89,8 +98,11 @@ export class Context { * * To read more about the messages sent and responses received by this client, such as * "initialize," read [the Language Server Protocol specification](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize). + * + * In order to synchronously wait for the client to be completely ready, + * we need to mark the function as asynchronous **/ - startClient(): void { + async startClient(): Promise { const executable: lc.Executable = { command: this.configuration.serverPath, }; @@ -122,5 +134,19 @@ export class Context { log.info('Starting client...'); const disposable = client.start(); this.extensionContext.subscriptions.push(disposable); + this.client = client; + + // Wait for the Move Language Server initialization to complete, + // especially the first symbol table parsing is completed + await this.client.onReady(); + } + + /** + * Returns the client that this extension interacts with. + * + * @returns lc.LanguageClient + */ + getClient(): lc.LanguageClient | undefined { + return this.client; } -} +} // Context diff --git a/language/move-analyzer/editors/code/src/main.ts b/language/move-analyzer/editors/code/src/main.ts index f2ec1edc8a..29edca6a59 100644 --- a/language/move-analyzer/editors/code/src/main.ts +++ b/language/move-analyzer/editors/code/src/main.ts @@ -6,8 +6,11 @@ import { Configuration } from './configuration'; import { Context } from './context'; import { Extension } from './extension'; import { log } from './log'; + import * as childProcess from 'child_process'; import * as vscode from 'vscode'; +import * as commands from './commands'; + /** * An extension command that displays the version of the server that this extension @@ -40,8 +43,11 @@ async function serverVersion(context: Readonly): Promise { * * Activation events for this extension are listed in its `package.json` file, under the key * `"activationEvents"`. + * + * In order to achieve synchronous activation, mark the function as an asynchronous function, + * so that you can wait for the activation to complete by await */ -export function activate(extensionContext: Readonly): void { +export async function activate(extensionContext: Readonly): Promise { const extension = new Extension(); log.info(`${extension.identifier} version ${extension.version}`); @@ -66,5 +72,6 @@ export function activate(extensionContext: Readonly): v context.configureLanguage(); // All other utilities provided by this extension occur via the language server. - context.startClient(); + await context.startClient(); + context.registerCommand('textDocumentDocumentSymbol', commands.textDocumentDocumentSymbol); } diff --git a/language/move-analyzer/editors/code/tests/index.ts b/language/move-analyzer/editors/code/tests/index.ts index 8b7cd74b5a..1660a4dc49 100644 --- a/language/move-analyzer/editors/code/tests/index.ts +++ b/language/move-analyzer/editors/code/tests/index.ts @@ -14,13 +14,21 @@ import * as path from 'path'; /* eslint-disable */ // deno-lint-ignore require-await export async function run(): Promise { + // dev mode + const mode = process.env['mode'] || 'test'; + if (mode === 'dev') { + return new Promise((resolve) => { + setTimeout(resolve, 1000 * 60 * 15); // Development mode, set a timeout of 15 minutes + }); + } + /* eslint-disable */ const suite = new Mocha({ ui: 'tdd', color: true, // The default timeout of 2000 miliseconds can sometimes be too quick, since the extension // tests need to launch VS Code first. - timeout: 5000, + timeout: 10000, }); const testsRoot = path.resolve(__dirname, '..'); diff --git a/language/move-analyzer/editors/code/tests/lsp-demo/Move.toml b/language/move-analyzer/editors/code/tests/lsp-demo/Move.toml new file mode 100644 index 0000000000..47ddc67395 --- /dev/null +++ b/language/move-analyzer/editors/code/tests/lsp-demo/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Symbols" +version = "0.0.1" + +[dependencies] +MoveStdlib = { local = "../../../../../../move-stdlib/", addr_subst = { "std" = "0x1" } } + +[addresses] +Symbols = "0xCAFE" diff --git a/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace b/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace new file mode 100644 index 0000000000..4651fb61d0 --- /dev/null +++ b/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "move-analyzer.server.path": "../../../../../../target/debug/move-analyzer" + } +} diff --git a/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace b/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace new file mode 100644 index 0000000000..087aded48f --- /dev/null +++ b/language/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "move-analyzer.server.path": "../../../../target/debug/move-analyzer" + } +} diff --git a/language/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move b/language/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move new file mode 100644 index 0000000000..d1454454b6 --- /dev/null +++ b/language/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move @@ -0,0 +1,18 @@ +module Symbols::M1 { + + const SOME_CONST: u64 = 42; + + struct SomeOtherStruct has drop { + some_field: u64, + } + + public fun some_other_struct(v: u64): SomeOtherStruct { + SomeOtherStruct { some_field: v } + } + + #[test] + #[expected_failure] + fun this_is_a_test() { + 1/0; + } +} diff --git a/language/move-analyzer/editors/code/tests/lsp.test.ts b/language/move-analyzer/editors/code/tests/lsp.test.ts new file mode 100644 index 0000000000..5a0a658f95 --- /dev/null +++ b/language/move-analyzer/editors/code/tests/lsp.test.ts @@ -0,0 +1,52 @@ +import * as assert from 'assert'; +import * as Mocha from 'mocha'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import * as lc from 'vscode-languageclient'; + +Mocha.suite('LSP', () => { + Mocha.test('textDocument/documentSymbol', async () => { + const ext = vscode.extensions.getExtension('move.move-analyzer'); + assert.ok(ext); + + await ext.activate(); // Synchronous waiting for activation to complete + + // 1. get workdir + const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; + + // 2. open doc + const docs = await vscode.workspace.openTextDocument(path.join(workDir, 'sources/M1.move')); + await vscode.window.showTextDocument(docs); + + // 3. execute command + const params: lc.DocumentSymbolParams = { + textDocument: { + uri: docs.uri.toString(), + }, + }; + + const syms: Array | undefined = await + vscode.commands.executeCommand( + 'move-analyzer.textDocumentDocumentSymbol', params, + ); + + assert.ok(syms); + assert.deepStrictEqual(syms[0]?.kind, lc.SymbolKind.Module); + assert.deepStrictEqual(syms[0].name, 'M1'); + + assert.ok(syms[0].children); + assert.deepStrictEqual(syms[0]?.children[0]?.kind, lc.SymbolKind.Constant); + assert.deepStrictEqual(syms[0]?.children[0].name, 'SOME_CONST'); + assert.deepStrictEqual(syms[0]?.children[1]?.kind, lc.SymbolKind.Struct); + assert.deepStrictEqual(syms[0]?.children[1].name, 'SomeOtherStruct'); + assert.ok(syms[0].children[1].children); + assert.deepStrictEqual(syms[0]?.children[1]?.children[0]?.kind, lc.SymbolKind.Field); + assert.deepStrictEqual(syms[0]?.children[1]?.children[0]?.name, 'some_field'); + assert.deepStrictEqual(syms[0]?.children[1].name, 'SomeOtherStruct'); + assert.deepStrictEqual(syms[0]?.children[2]?.kind, lc.SymbolKind.Function); + assert.deepStrictEqual(syms[0]?.children[2].name, 'some_other_struct'); + assert.deepStrictEqual(syms[0]?.children[3]?.kind, lc.SymbolKind.Function); + assert.deepStrictEqual(syms[0]?.children[3].name, 'this_is_a_test'); + assert.deepStrictEqual(syms[0]?.children[3]?.detail, '["test", "expected_failure"]'); + }); +}); diff --git a/language/move-analyzer/editors/code/tests/runTests.ts b/language/move-analyzer/editors/code/tests/runTests.ts index 5bb578e7a4..a8cd46f285 100644 --- a/language/move-analyzer/editors/code/tests/runTests.ts +++ b/language/move-analyzer/editors/code/tests/runTests.ts @@ -9,8 +9,16 @@ * https://code.visualstudio.com/api/working-with-extensions/testing-extension#the-test-script */ +import * as os from 'os'; import * as path from 'path'; -import { runTests } from '@vscode/test-electron'; +import * as cp from 'child_process'; +import * as fs from 'fs'; +import * as fse from 'fs-extra'; +import { + runTests, + downloadAndUnzipVSCode, + resolveCliArgsFromVSCodeExecutablePath, +} from '@vscode/test-electron'; /** * Launches a VS Code instance to run tests. @@ -18,7 +26,7 @@ import { runTests } from '@vscode/test-electron'; * This is essentially a TypeScript program that executes the "VS Code Tokenizer Tests" launch * target defined in this repository's `.vscode/launch.json`. */ -async function main(): Promise { +async function runVSCodeTest(vscodeVersion: string): Promise { try { // The `--extensionDevelopmentPath` argument passed to VS Code. This should point to the // directory that contains the extension manifest file, `package.json`. @@ -28,12 +36,45 @@ async function main(): Promise { // program that is considered to be the "test suite" for the extension. const extensionTestsPath = path.resolve(__dirname, 'index.js'); + // The workspace + let testWorkspacePath = path.resolve(__dirname, './lsp-demo/lsp-demo.code-workspace'); + if (process.platform === 'win32') { + testWorkspacePath = path.resolve(__dirname, './lsp-demo/lsp-demo-win.code-workspace'); + } + + // Install vscode and depends extension + const vscodeExecutablePath = await downloadAndUnzipVSCode(vscodeVersion); + const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); + const newCli = cli ?? 'code'; + cp.spawnSync(newCli, [...args, '--install-extension', 'damirka.move-syntax', '--force'], { + encoding: 'utf-8', + stdio: 'inherit', + }); + + // Because the default vscode userDataDir is too long, + // v1.69.2 will report an error when running test. + // So generate a short + const userDataDir = path.join(os.tmpdir(), 'vscode-test', vscodeVersion); + if (!fs.existsSync(userDataDir)) { + fse.mkdirsSync(userDataDir); + } + // Download VS Code, unzip it, and run the "test suite" program. - await runTests({ extensionDevelopmentPath, extensionTestsPath }); + await runTests({ + vscodeExecutablePath: vscodeExecutablePath, + extensionDevelopmentPath, + extensionTestsPath, + launchArgs: [testWorkspacePath, '--user-data-dir', userDataDir], + }); } catch (_err: unknown) { console.error('Failed to run tests'); process.exit(1); } } +async function main(): Promise { + await runVSCodeTest('1.64.0'); // Test with vscode v1.64.0 + await runVSCodeTest('1.69.2'); // Test with vscode v1.69.2 +} + void main(); diff --git a/language/move-analyzer/editors/code/types/vscode-test-electron.d.ts b/language/move-analyzer/editors/code/types/vscode-test-electron.d.ts deleted file mode 100644 index e325fbf6ab..0000000000 --- a/language/move-analyzer/editors/code/types/vscode-test-electron.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -// FIXME: The vscode-test `runTests` function is implemented in TypeScript and has type annotations: -// https://github.com/microsoft/vscode-test/blob/v1.6.1/lib/runTest.ts#L86 -// But I don't know where, if anywhere, those types are published, so to appease the TypeScript -// compiler's type-checker, I declare the function type in this file. -declare module '@vscode/test-electron' { - export interface TestOptions { - extensionDevelopmentPath?: string; - extensionTestsPath?: string; - // N.B.: vscode-test's definition of `TestOptions` contains many more fields: - // https://github.com/microsoft/vscode-test/blob/v1.6.1/lib/runTest.ts#L9-L79 - } - - export function runTests(options: TestOptions): Thenable; -} diff --git a/language/move-analyzer/src/bin/move-analyzer.rs b/language/move-analyzer/src/bin/move-analyzer.rs index 9d2b0f39bc..e33bc87eb1 100644 --- a/language/move-analyzer/src/bin/move-analyzer.rs +++ b/language/move-analyzer/src/bin/move-analyzer.rs @@ -106,6 +106,7 @@ fn main() { symbols::DEFS_AND_REFS_SUPPORT, )), references_provider: Some(OneOf::Left(symbols::DEFS_AND_REFS_SUPPORT)), + document_symbol_provider: Some(OneOf::Left(true)), ..Default::default() }) .expect("could not serialize server capabilities"); @@ -235,6 +236,9 @@ fn on_request(context: &Context, request: &Request) { lsp_types::request::HoverRequest::METHOD => { symbols::on_hover_request(context, request, &context.symbols.lock().unwrap()); } + lsp_types::request::DocumentSymbolRequest::METHOD => { + symbols::on_document_symbol_request(context, request, &context.symbols.lock().unwrap()); + } _ => eprintln!("handle request '{}' from client", request.method), } } diff --git a/language/move-analyzer/src/symbols.rs b/language/move-analyzer/src/symbols.rs index f2717837a1..10140a17c7 100644 --- a/language/move-analyzer/src/symbols.rs +++ b/language/move-analyzer/src/symbols.rs @@ -57,9 +57,11 @@ use crossbeam::channel::Sender; use im::ordmap::OrdMap; use lsp_server::{Request, RequestId}; use lsp_types::{ - request::GotoTypeDefinitionParams, Diagnostic, GotoDefinitionParams, Hover, HoverContents, - HoverParams, LanguageString, Location, MarkedString, Position, Range, ReferenceParams, + request::GotoTypeDefinitionParams, Diagnostic, DocumentSymbol, DocumentSymbolParams, + GotoDefinitionParams, Hover, HoverContents, HoverParams, LanguageString, Location, + MarkedString, Position, Range, ReferenceParams, SymbolKind, }; + use std::{ cmp, collections::{BTreeMap, BTreeSet, HashMap}, @@ -148,30 +150,41 @@ pub struct UseDef { } /// Definition of a struct field -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] struct FieldDef { name: Symbol, start: Position, } /// Definition of a struct -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] struct StructDef { name_start: Position, field_defs: Vec, } +#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +struct FunctionDef { + name: Symbol, + start: Position, + attrs: Vec, +} + /// Module-level definitions -#[derive(Debug)] +#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] struct ModuleDefs { /// File where this module is located fhash: FileHash, + /// Location where this module is located + start: Position, + /// Module name + name: ModuleIdent_, /// Struct definitions structs: BTreeMap, /// Const definitions constants: BTreeMap, /// Function definitions - functions: BTreeMap, + functions: BTreeMap, } /// Data used during symbolication @@ -190,7 +203,7 @@ pub struct Symbolicator { /// Maps a line number to a list of use-def pairs on a given line (use-def set is sorted by /// col_start) -#[derive(Debug)] +#[derive(Debug, Clone, Eq, PartialEq)] struct UseDefMap(BTreeMap>); /// Result of the symbolication process @@ -201,6 +214,8 @@ pub struct Symbols { file_use_defs: BTreeMap, /// A mapping from file hashes to file names file_name_mapping: BTreeMap, + /// A mapping from filePath to ModuleDefs + file_mods: BTreeMap>, } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] @@ -540,6 +555,7 @@ impl Symbols { } self.file_use_defs.extend(other.file_use_defs); self.file_name_mapping.extend(other.file_name_mapping); + self.file_mods.extend(other.file_mods); } } @@ -635,13 +651,33 @@ impl Symbolicator { let mut mod_outer_defs = BTreeMap::new(); let mut mod_use_defs = BTreeMap::new(); + let mut file_mods = BTreeMap::new(); + for (pos, module_ident, module_def) in modules { - let (defs, symbols) = - Self::get_mod_outer_defs(&pos, module_def, &files, &file_id_mapping); + let (defs, symbols) = Self::get_mod_outer_defs( + &pos, + &sp(pos, *module_ident), + module_def, + &files, + &file_id_mapping, + ); + + let cloned_defs = defs.clone(); + let path = file_name_mapping.get(&cloned_defs.fhash.clone()).unwrap(); + file_mods + .entry( + dunce::canonicalize(path.as_str()) + .unwrap_or_else(|_| PathBuf::from(path.as_str())), + ) + .or_insert_with(BTreeSet::new) + .insert(cloned_defs); + mod_outer_defs.insert(*module_ident, defs); mod_use_defs.insert(*module_ident, symbols); } + eprintln!("get_symbols loaded file_mods length: {}", file_mods.len()); + let mut symbolicator = Symbolicator { mod_outer_defs, files, @@ -675,7 +711,11 @@ impl Symbolicator { references, file_use_defs, file_name_mapping, + file_mods, }; + + eprintln!("get_symbols load complete"); + Ok((Some(symbols), ide_diagnostics)) } @@ -685,6 +725,7 @@ impl Symbolicator { file_use_defs: BTreeMap::new(), references: BTreeMap::new(), file_name_mapping: BTreeMap::new(), + file_mods: BTreeMap::new(), } } @@ -693,6 +734,7 @@ impl Symbolicator { /// Get symbols for outer definitions in the module (functions, structs, and consts) fn get_mod_outer_defs( loc: &Loc, + mod_ident: &ModuleIdent, mod_def: &ModuleDefinition, files: &SimpleFiles, file_id_mapping: &HashMap, @@ -748,7 +790,7 @@ impl Symbolicator { constants.insert(*name, name_start); } - for (pos, name, _) in &mod_def.functions { + for (pos, name, func) in &mod_def.functions { let name_start = match Self::get_start_loc(&pos, files, file_id_mapping) { Some(s) => s, None => { @@ -756,18 +798,55 @@ impl Symbolicator { continue; } }; - functions.insert(*name, name_start); + functions.insert( + *name, + FunctionDef { + name: *name, + start: name_start, + attrs: func + .attributes + .clone() + .iter() + .map(|(_loc, name, _attr)| name.to_string()) + .collect(), + }, + ); } + let use_def_map = UseDefMap::new(); + + let name = mod_ident.value; let fhash = loc.file_hash(); + let start = match Self::get_start_loc(&loc, files, file_id_mapping) { + Some(s) => s, + None => { + debug_assert!(false); + return ( + ModuleDefs { + fhash, + start: Position { + line: 0, + character: 0, + }, + name, + structs, + constants, + functions, + }, + use_def_map, + ); + } + }; + let module_defs = ModuleDefs { + name, + start, fhash, structs, constants, functions, }; - let use_def_map = UseDefMap::new(); (module_defs, use_def_map) } @@ -1505,7 +1584,7 @@ impl Symbolicator { use_name, use_pos, |use_name, name_start, mod_defs| match mod_defs.functions.get(use_name) { - Some(def_start) => { + Some(func_def) => { use_defs.insert( name_start.line, UseDef::new( @@ -1513,7 +1592,7 @@ impl Symbolicator { use_pos.file_hash(), name_start, self.mod_outer_defs.get(&module_ident.value).unwrap().fhash, - *def_start, + func_def.start, use_name, use_type.clone(), self.ident_type_def_loc(&use_type), @@ -1995,6 +2074,145 @@ pub fn on_use_request( } } +/// Handles document symbol request of the language server +#[allow(deprecated)] +pub fn on_document_symbol_request(context: &Context, request: &Request, symbols: &Symbols) { + let parameters = serde_json::from_value::(request.params.clone()) + .expect("could not deserialize document symbol request"); + + let fpath = parameters.text_document.uri.to_file_path().unwrap(); + eprintln!("on_document_symbol_request: {:?}", fpath); + + let empty_mods: BTreeSet = BTreeSet::new(); + let mods = symbols.file_mods.get(&fpath).unwrap_or(&empty_mods); + + let mut defs: Vec = vec![]; + for mod_def in mods { + let name = mod_def.name.module.clone().to_string(); + let detail = Some(mod_def.name.clone().to_string()); + let kind = SymbolKind::Module; + let range = Range { + start: mod_def.start, + end: mod_def.start, + }; + + let mut children = vec![]; + + // handle constants + let cloned_const_def = mod_def.constants.clone(); + for (sym, const_def_pos) in cloned_const_def { + let const_range = Range { + start: const_def_pos, + end: const_def_pos, + }; + + children.push(DocumentSymbol { + name: sym.clone().to_string(), + detail: None, + kind: SymbolKind::Constant, + range: const_range, + selection_range: const_range, + children: None, + tags: Some(vec![]), + deprecated: Some(false), + }); + } + + // handle structs + let cloned_struct_def = mod_def.structs.clone(); + for (sym, struct_def) in cloned_struct_def { + let struct_range = Range { + start: struct_def.name_start, + end: struct_def.name_start, + }; + + let mut fields: Vec = vec![]; + handle_struct_fields(struct_def, &mut fields); + + children.push(DocumentSymbol { + name: sym.clone().to_string(), + detail: None, + kind: SymbolKind::Struct, + range: struct_range, + selection_range: struct_range, + children: Some(fields), + tags: Some(vec![]), + deprecated: Some(false), + }); + } + + // handle functions + let cloned_func_def = mod_def.functions.clone(); + for (sym, func_def) in cloned_func_def { + let func_range = Range { + start: func_def.start, + end: func_def.start, + }; + + let mut detail = None; + if !func_def.attrs.is_empty() { + detail = Some(format!("{:?}", func_def.attrs)); + } + + children.push(DocumentSymbol { + name: sym.clone().to_string(), + detail, + kind: SymbolKind::Function, + range: func_range, + selection_range: func_range, + children: None, + tags: Some(vec![]), + deprecated: Some(false), + }); + } + + defs.push(DocumentSymbol { + name, + detail, + kind, + range, + selection_range: range, + children: Some(children), + tags: Some(vec![]), + deprecated: Some(false), + }); + } + + // unwrap will succeed based on the logic above which the compiler is unable to figure out + let response = lsp_server::Response::new_ok(request.id.clone(), defs); + if let Err(err) = context + .connection + .sender + .send(lsp_server::Message::Response(response)) + { + eprintln!("could not send use response: {:?}", err); + } +} + +/// Helper function to handle struct fields +#[allow(deprecated)] +fn handle_struct_fields(struct_def: StructDef, fields: &mut Vec) { + let clonded_fileds = struct_def.field_defs; + + for field_def in clonded_fileds { + let field_range = Range { + start: field_def.start, + end: field_def.start, + }; + + fields.push(DocumentSymbol { + name: field_def.name.clone().to_string(), + detail: None, + kind: SymbolKind::Field, + range: field_range, + selection_range: field_range, + children: None, + tags: Some(vec![]), + deprecated: Some(false), + }); + } +} + #[cfg(test)] fn assert_use_def( mod_symbols: &UseDefMap, From 7072c081acbf3b5987723ca706edc77821ebd9b7 Mon Sep 17 00:00:00 2001 From: Adam Welc Date: Tue, 2 Aug 2022 08:42:06 -0700 Subject: [PATCH 026/169] [cli] Added the ability to add custom content to generated Move.toml files (#331) --- language/tools/move-cli/src/base/new.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/language/tools/move-cli/src/base/new.rs b/language/tools/move-cli/src/base/new.rs index c1996ed5a7..6dbfbeaf1d 100644 --- a/language/tools/move-cli/src/base/new.rs +++ b/language/tools/move-cli/src/base/new.rs @@ -34,6 +34,7 @@ impl New { "0.0.0", [(MOVE_STDLIB_PACKAGE_NAME, MOVE_STDLIB_PACKAGE_PATH)], [(MOVE_STDLIB_ADDR_NAME, MOVE_STDLIB_ADDR_VALUE)], + "", ) } @@ -43,6 +44,7 @@ impl New { version: &str, deps: impl IntoIterator, addrs: impl IntoIterator, + custom: &str, // anything else that needs to end up being in Move.toml (or empty string) ) -> anyhow::Result<()> { // TODO warn on build config flags let Self { name } = self; @@ -76,6 +78,9 @@ version = \"{version}\" for (addr_name, addr_val) in addrs { writeln!(w, "{addr_name} = \"{addr_val}\"")?; } + if !custom.is_empty() { + writeln!(w, "{}", custom)?; + } Ok(()) } } From ebe2602a8aa0c9e979daaedd5058a7987da47ea5 Mon Sep 17 00:00:00 2001 From: Junkil Park Date: Tue, 2 Aug 2022 09:30:06 -0700 Subject: [PATCH 027/169] Bump up the boogie version to 2.15.7 (#332) - Bumped up the boogie version to the latest one (2.15.7) - Updated `boogie_wrapper` to ignore the state information that Boogie produces as output --- language/move-prover/boogie-backend/src/boogie_wrapper.rs | 7 ++++++- language/move-prover/boogie-backend/src/options.rs | 2 +- scripts/dev_setup.sh | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/language/move-prover/boogie-backend/src/boogie_wrapper.rs b/language/move-prover/boogie-backend/src/boogie_wrapper.rs index bae2e32eb1..a2cc0f0f05 100644 --- a/language/move-prover/boogie-backend/src/boogie_wrapper.rs +++ b/language/move-prover/boogie-backend/src/boogie_wrapper.rs @@ -565,7 +565,12 @@ impl<'env> BoogieWrapper<'env> { if let Some(cap) = MODEL_REGION.captures(&out[*at..]) { *at = usize::saturating_add(*at, cap.get(0).unwrap().end()); - match model.parse(self, cap.name("mod").unwrap().as_str()) { + + // Cuts out the state info block which is not used currently. + let re = Regex::new(r"(?m)\*\*\* STATE(?s:.)*?\*\*\* END_STATE\n").unwrap(); + let remnant = re.replace(cap.name("mod").unwrap().as_str(), ""); + + match model.parse(self, remnant.as_ref()) { Ok(_) => {} Err(parse_error) => { let context_module = self diff --git a/language/move-prover/boogie-backend/src/options.rs b/language/move-prover/boogie-backend/src/options.rs index fe7f446be1..2d712f9f02 100644 --- a/language/move-prover/boogie-backend/src/options.rs +++ b/language/move-prover/boogie-backend/src/options.rs @@ -19,7 +19,7 @@ const DEFAULT_BOOGIE_FLAGS: &[&str] = &[ "-proverOpt:O:model_validate=true", ]; -const MIN_BOOGIE_VERSION: &str = "2.13.4"; +const MIN_BOOGIE_VERSION: &str = "2.15.7"; const MIN_Z3_VERSION: &str = "4.10.2"; const MIN_CVC5_VERSION: &str = "0.0.3"; diff --git a/scripts/dev_setup.sh b/scripts/dev_setup.sh index a228e993f5..c72e775bd1 100755 --- a/scripts/dev_setup.sh +++ b/scripts/dev_setup.sh @@ -18,7 +18,7 @@ set -eo pipefail Z3_VERSION=4.10.2 CVC5_VERSION=0.0.3 DOTNET_VERSION=6.0 -BOOGIE_VERSION=2.13.4 +BOOGIE_VERSION=2.15.7 SOLC_VERSION="v0.8.11+commit.d7f03943" SCRIPT_PATH="$(cd "$(dirname "$0")" >/dev/null 2>&1 && pwd)" From 8f305e2209c2f5d493ed19078d45981c41cb86f9 Mon Sep 17 00:00:00 2001 From: Zekun Li Date: Mon, 1 Aug 2022 16:40:13 -0700 Subject: [PATCH 028/169] [error] move the debug assertion properly so it doesn't panic under OUT_OF_GAS --- language/move-binary-format/src/errors.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/language/move-binary-format/src/errors.rs b/language/move-binary-format/src/errors.rs index 9f56314968..50353c46bf 100644 --- a/language/move-binary-format/src/errors.rs +++ b/language/move-binary-format/src/errors.rs @@ -82,10 +82,17 @@ impl VMError { VMStatus::Error(StatusCode::ABORTED) } - // TODO Errors for OUT_OF_GAS do not always have index set (major_status, sub_status, location) if major_status.status_type() == StatusType::Execution => { + let abort_location = match &location { + Location::Script => vm_status::AbortLocation::Script, + Location::Module(id) => vm_status::AbortLocation::Module(id.clone()), + Location::Undefined => { + return VMStatus::Error(major_status); + } + }; + // Errors for OUT_OF_GAS do not always have index set: if it does not, it should already return above. debug_assert!( offsets.len() == 1, "Unexpected offsets. major_status: {:?}\ @@ -97,13 +104,6 @@ impl VMError { location, offsets ); - let abort_location = match location { - Location::Script => vm_status::AbortLocation::Script, - Location::Module(id) => vm_status::AbortLocation::Module(id), - Location::Undefined => { - return VMStatus::Error(major_status); - } - }; let (function, code_offset) = match offsets.pop() { None => { return VMStatus::Error(major_status); From 0f07007d514841fcdb66a0878b7c87a433953aa4 Mon Sep 17 00:00:00 2001 From: Greg Nazario Date: Tue, 2 Aug 2022 12:59:27 -0700 Subject: [PATCH 029/169] [account-address] Allow fuzzy deserialize with or without 0x (#321) This allows us to deserialize human readable inputs to allow configs and other human readable things to be easier to parse --- language/move-core/types/src/account_address.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/move-core/types/src/account_address.rs b/language/move-core/types/src/account_address.rs index d09bff6c39..2ac41adddf 100644 --- a/language/move-core/types/src/account_address.rs +++ b/language/move-core/types/src/account_address.rs @@ -239,7 +239,7 @@ impl<'de> Deserialize<'de> for AccountAddress { { if deserializer.is_human_readable() { let s = ::deserialize(deserializer)?; - AccountAddress::from_hex(s).map_err(D::Error::custom) + AccountAddress::from_str(&s).map_err(D::Error::custom) } else { // In order to preserve the Serde data model and help analysis tools, // make sure to wrap our value in a container with the same name From f618b1b1c0d59960b49ff15147ecdb5de8e72408 Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Wed, 3 Aug 2022 16:38:54 -0400 Subject: [PATCH 030/169] [move-prover] do not remap moved nodes in borrow analysis (#335) * [move-prover] do not remap moved nodes in borrow analysis If a local is first mutably borrowed and later moved in a loop, the reference will have two parents (and hence, write-back edges): - one to the original local and - the other to the LHS of the moved local. This can be shown in the following code: ```move loop { let s = S { x : 100 }; let r = &mut s; if (r.x >= limit) { r.x = limit; } t = move(s); } ``` The borrow analysis will conclude that the reference `r` has two parents, `s` and `t`. This bug can only happen in loops due to the fact that the borrow analysis is essentially an abstract interpretation pass and the join operator for the `BorrowInfo` is a set union. Although for any single pass on the loop body, `r` can either point to `s` or `t`. After the join, `r` points to both `s` and `t`, which is incorrect. This commit fixes this issue by dropping the `remap` function on borrowed edges for a moved node. Specifically: ``` t = move(s); ``` - Prior to this fix, all references derived from `s` will be remapped to be deriving from `t` (which does not seem to be correct). - After this fix, the references derived from `s` remain pointing to `s` During the process, the `moved_nodes` in the `BorrowInfo` seems to be obsolete as well, so it is removed, which also causes the `exp` test cases to be updated.` * fixup! [move-prover] do not remap moved nodes in borrow analysis --- .../bytecode/src/borrow_analysis.rs | 71 ++---- .../bytecode/tests/borrow/basic_test.exp | 21 +- .../bytecode/tests/borrow/function_call.exp | 16 +- .../bytecode/tests/borrow/hyper_edge.exp | 13 +- .../tests/borrow_strong/basic_test.exp | 33 ++- .../bytecode/tests/borrow_strong/mut_ref.exp | 204 +++++++----------- .../regression/moved_local_with_refs.move | 33 +++ 7 files changed, 164 insertions(+), 227 deletions(-) create mode 100644 language/move-prover/tests/sources/regression/moved_local_with_refs.move diff --git a/language/move-prover/bytecode/src/borrow_analysis.rs b/language/move-prover/bytecode/src/borrow_analysis.rs index 3ba12dc4b3..ca7ed42da9 100644 --- a/language/move-prover/bytecode/src/borrow_analysis.rs +++ b/language/move-prover/bytecode/src/borrow_analysis.rs @@ -29,9 +29,6 @@ pub struct BorrowInfo { /// other nodes which are alive borrow from them. live_nodes: SetDomain, - /// Contains the nodes which have been moved via a move instruction. - moved_nodes: SetDomain, - /// Forward borrow information. borrowed_by: MapDomain>, @@ -151,10 +148,7 @@ impl BorrowInfo { } pub fn is_empty(&self) -> bool { - self.live_nodes.is_empty() - && self.moved_nodes.is_empty() - && self.borrowed_by.is_empty() - && self.borrows_from.is_empty() + self.live_nodes.is_empty() && self.borrowed_by.is_empty() && self.borrows_from.is_empty() } pub fn borrow_info_str(&self, func_target: &FunctionTarget<'_>) -> String { @@ -171,13 +165,6 @@ impl BorrowInfo { .map(|node| format!("{}", node.display(func_target))) .join(", "), ); - add( - "moved_nodes", - self.moved_nodes - .iter() - .map(|node| format!("{}", node.display(func_target))) - .join(", "), - ); let borrows_str = |(node1, borrows): (&BorrowNode, &SetDomain<(BorrowNode, BorrowEdge)>)| { format!( @@ -208,7 +195,7 @@ impl BorrowInfo { self.live_nodes.insert(node); } - fn remove_node(&mut self, node: &BorrowNode) { + fn del_node(&mut self, node: &BorrowNode) { self.live_nodes.remove(node); } @@ -324,11 +311,10 @@ impl BorrowInfo { if let BorrowNode::Reference(in_idx) = in_node { let actual_in_node = BorrowNode::Reference(get_in(*in_idx)); self.add_edge( - actual_in_node.clone(), + actual_in_node, out_node.clone(), edge.instantiate(callee_targs), ); - self.moved_nodes.insert(actual_in_node); } } } else { @@ -510,26 +496,6 @@ impl<'a> BorrowAnalysis<'a> { BorrowNode::LocalRoot(idx) } } - - fn remap_borrow_node(&self, state: &mut BorrowInfo, from: &BorrowNode, to: &BorrowNode) { - let remap = |node: BorrowNode| if &node == from { to.clone() } else { node }; - state.live_nodes = std::mem::take(&mut state.live_nodes) - .into_iter() - .map(remap) - .collect(); - state.borrowed_by = std::mem::take(&mut state.borrowed_by) - .into_iter() - .map(|(src, dests)| { - ( - remap(src), - dests - .into_iter() - .map(|(node, edges)| (remap(node), edges)) - .collect(), - ) - }) - .collect() - } } impl<'a> TransferFunctions for BorrowAnalysis<'a> { @@ -542,18 +508,31 @@ impl<'a> TransferFunctions for BorrowAnalysis<'a> { .livevar_annotation .get_live_var_info_at(code_offset) .expect("livevar annotation"); + match instr { Assign(_, dest, src, kind) => { let dest_node = self.borrow_node(*dest); + state.add_node(dest_node.clone()); + let src_node = self.borrow_node(*src); match kind { AssignKind::Move => { - self.remap_borrow_node(state, &src_node, &dest_node); - state.moved_nodes.insert(src_node); + assert!(!self.func_target.get_local_type(*src).is_reference()); + assert!(!self.func_target.get_local_type(*dest).is_reference()); + state.del_node(&src_node); } - AssignKind::Copy | AssignKind::Store => { - state.add_node(dest_node.clone()); - state.add_edge(src_node, dest_node, BorrowEdge::Direct); + AssignKind::Copy => { + assert!(!self.func_target.get_local_type(*src).is_reference()); + assert!(!self.func_target.get_local_type(*dest).is_reference()); + } + AssignKind::Store => { + if self.func_target.get_local_type(*src).is_mutable_reference() { + assert!(self + .func_target + .get_local_type(*dest) + .is_mutable_reference()); + state.add_edge(src_node, dest_node, BorrowEdge::Direct); + } } } } @@ -644,14 +623,13 @@ impl<'a> TransferFunctions for BorrowAnalysis<'a> { } // Update live_vars. - for idx in livevar_annotation_at .before .difference(&livevar_annotation_at.after) { if self.func_target.get_local_type(*idx).is_reference() { let node = self.borrow_node(*idx); - state.remove_node(&node); + state.del_node(&node); } } } @@ -662,11 +640,8 @@ impl<'a> DataflowAnalysis for BorrowAnalysis<'a> {} impl AbstractDomain for BorrowInfo { fn join(&mut self, other: &Self) -> JoinResult { let live_changed = self.live_nodes.join(&other.live_nodes); - let moved_changed = self.moved_nodes.join(&other.moved_nodes); let borrowed_changed = self.borrowed_by.join(&other.borrowed_by); - borrowed_changed - .combine(moved_changed) - .combine(live_changed) + borrowed_changed.combine(live_changed) } } diff --git a/language/move-prover/bytecode/tests/borrow/basic_test.exp b/language/move-prover/bytecode/tests/borrow/basic_test.exp index 6692b3b8dc..4b5f1d2894 100644 --- a/language/move-prover/bytecode/tests/borrow/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow/basic_test.exp @@ -277,9 +277,9 @@ fun TestBorrow::test1(): TestBorrow::R { # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 6: $t7 := move($t0) - # moved_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t7) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} - # borrows_from: Reference($t4) -> {(@, LocalRoot($t7))}, Reference($t5) -> {(.x (u64), Reference($t4))} + # live_nodes: LocalRoot($t7) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} + # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 7: return $t7 } @@ -338,9 +338,9 @@ fun TestBorrow::test4(): TestBorrow::R { # borrowed_by: LocalRoot($t0) -> {(@, Reference($t3))} # borrows_from: Reference($t3) -> {(@, LocalRoot($t0))} 5: $t5 := move($t0) - # moved_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t5) -> {(@, Reference($t3))} - # borrows_from: Reference($t3) -> {(@, LocalRoot($t5))} + # live_nodes: LocalRoot($t5) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t3))} + # borrows_from: Reference($t3) -> {(@, LocalRoot($t0))} 6: return $t5 } @@ -379,22 +379,19 @@ fun TestBorrow::test6(): TestBorrow::R { # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))} 3: $t5 := TestBorrow::test5($t4) # live_nodes: Reference($t5) - # moved_nodes: Reference($t4) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 4: $t6 := 0 # live_nodes: Reference($t5) - # moved_nodes: Reference($t4) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 5: TestBorrow::test2($t5, $t6) - # moved_nodes: Reference($t4) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 6: $t7 := move($t0) - # moved_nodes: LocalRoot($t0), Reference($t4) - # borrowed_by: LocalRoot($t7) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} - # borrows_from: Reference($t4) -> {(@, LocalRoot($t7))}, Reference($t5) -> {(.x (u64), Reference($t4))} + # live_nodes: LocalRoot($t7) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))}, Reference($t4) -> {(.x (u64), Reference($t5))} + # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))}, Reference($t5) -> {(.x (u64), Reference($t4))} 7: return $t7 } diff --git a/language/move-prover/bytecode/tests/borrow/function_call.exp b/language/move-prover/bytecode/tests/borrow/function_call.exp index fbafcf7783..a5391696c2 100644 --- a/language/move-prover/bytecode/tests/borrow/function_call.exp +++ b/language/move-prover/bytecode/tests/borrow/function_call.exp @@ -190,10 +190,9 @@ public fun vector::singleton<#0>($t0|e: #0): vector<#0> { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 3: $t3 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t2))} - # borrows_from: Reference($t2) -> {(@, LocalRoot($t3))} + # live_nodes: LocalRoot($t0), LocalRoot($t3) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 4: return $t3 } @@ -222,12 +221,10 @@ fun MultiLayerCalling::inner($t0|has_vector: &mut MultiLayerCalling::HasVector): # borrows_from: Reference($t1) -> {(.v (vector), Reference($t0))} 2: $t3 := vector::borrow_mut($t1, $t2) # live_nodes: Reference($t0), Reference($t3) - # moved_nodes: Reference($t1) # borrowed_by: Reference($t0) -> {(.v (vector), Reference($t1))}, Reference($t1) -> {([], Reference($t3))} # borrows_from: Reference($t1) -> {(.v (vector), Reference($t0))}, Reference($t3) -> {([], Reference($t1))} 3: trace_local[has_vector]($t0) # live_nodes: Reference($t3) - # moved_nodes: Reference($t1) # borrowed_by: Reference($t0) -> {(.v (vector), Reference($t1))}, Reference($t1) -> {([], Reference($t3))} # borrows_from: Reference($t1) -> {(.v (vector), Reference($t0))}, Reference($t3) -> {([], Reference($t1))} 4: return $t3 @@ -240,12 +237,10 @@ fun MultiLayerCalling::mid($t0|has_vector: &mut MultiLayerCalling::HasVector): & # live_nodes: Reference($t0) 0: $t1 := MultiLayerCalling::inner($t0) # live_nodes: Reference($t0), Reference($t1) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t1))} # borrows_from: Reference($t1) -> {(.v (vector)/[], Reference($t0))} 1: trace_local[has_vector]($t0) # live_nodes: Reference($t1) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t1))} # borrows_from: Reference($t1) -> {(.v (vector)/[], Reference($t0))} 2: return $t1 @@ -261,26 +256,21 @@ fun MultiLayerCalling::outer($t0|has_vector: &mut MultiLayerCalling::HasVector) # live_nodes: Reference($t0) 0: $t2 := MultiLayerCalling::mid($t0) # live_nodes: Reference($t0), Reference($t2) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))} # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))} 1: $t3 := borrow_field.v($t2) # live_nodes: Reference($t0), Reference($t3) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 2: $t4 := 42 # live_nodes: Reference($t0), Reference($t3) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 3: vector::push_back($t3, $t4) # live_nodes: Reference($t0) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 4: trace_local[has_vector]($t0) - # moved_nodes: Reference($t0) # borrowed_by: Reference($t0) -> {(.v (vector)/[], Reference($t2))}, Reference($t2) -> {(.v (vector), Reference($t3))} # borrows_from: Reference($t2) -> {(.v (vector)/[], Reference($t0))}, Reference($t3) -> {(.v (vector), Reference($t2))} 5: return () diff --git a/language/move-prover/bytecode/tests/borrow/hyper_edge.exp b/language/move-prover/bytecode/tests/borrow/hyper_edge.exp index 22a967414d..35a2f95de4 100644 --- a/language/move-prover/bytecode/tests/borrow/hyper_edge.exp +++ b/language/move-prover/bytecode/tests/borrow/hyper_edge.exp @@ -198,10 +198,9 @@ public fun vector::singleton<#0>($t0|e: #0): vector<#0> { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 3: $t3 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t2))} - # borrows_from: Reference($t2) -> {(@, LocalRoot($t3))} + # live_nodes: LocalRoot($t0), LocalRoot($t3) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 4: return $t3 } @@ -225,12 +224,10 @@ public fun Collection::borrow_mut<#0>($t0|c: &mut Collection::Collection<#0>, $t # borrows_from: Reference($t2) -> {(.items (vector<#0>), Reference($t0))} 1: $t3 := vector::borrow_mut<#0>($t2, $t1) # live_nodes: LocalRoot($t1), Reference($t0), Reference($t3) - # moved_nodes: Reference($t2) # borrowed_by: Reference($t0) -> {(.items (vector<#0>), Reference($t2))}, Reference($t2) -> {([], Reference($t3))} # borrows_from: Reference($t2) -> {(.items (vector<#0>), Reference($t0))}, Reference($t3) -> {([], Reference($t2))} 2: trace_local[c]($t0) # live_nodes: LocalRoot($t1), Reference($t3) - # moved_nodes: Reference($t2) # borrowed_by: Reference($t0) -> {(.items (vector<#0>), Reference($t2))}, Reference($t2) -> {([], Reference($t3))} # borrows_from: Reference($t2) -> {(.items (vector<#0>), Reference($t0))}, Reference($t3) -> {([], Reference($t2))} 3: return $t3 @@ -266,22 +263,18 @@ public fun Test::foo<#0>($t0|i: u64) { # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))} 2: $t4 := Collection::borrow_mut>($t3, $t0) # live_nodes: LocalRoot($t0), Reference($t4) - # moved_nodes: Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, Reference($t3) -> {(.items (vector>)/[], Reference($t4))} # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))}, Reference($t4) -> {(.items (vector>)/[], Reference($t3))} 3: $t5 := 0 # live_nodes: LocalRoot($t0), Reference($t4) - # moved_nodes: Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, Reference($t3) -> {(.items (vector>)/[], Reference($t4))} # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))}, Reference($t4) -> {(.items (vector>)/[], Reference($t3))} 4: $t6 := borrow_field>.value($t4) # live_nodes: LocalRoot($t0), Reference($t6) - # moved_nodes: Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, Reference($t3) -> {(.items (vector>)/[], Reference($t4))}, Reference($t4) -> {(.value (u64), Reference($t6))} # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))}, Reference($t4) -> {(.items (vector>)/[], Reference($t3))}, Reference($t6) -> {(.value (u64), Reference($t4))} 5: write_ref($t6, $t5) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t3) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t3))}, Reference($t3) -> {(.items (vector>)/[], Reference($t4))}, Reference($t4) -> {(.value (u64), Reference($t6))} # borrows_from: Reference($t3) -> {(@, LocalRoot($t1))}, Reference($t4) -> {(.items (vector>)/[], Reference($t3))}, Reference($t6) -> {(.value (u64), Reference($t4))} 6: return () diff --git a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp index bd081df2da..a83f2a88b9 100644 --- a/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp +++ b/language/move-prover/bytecode/tests/borrow_strong/basic_test.exp @@ -383,9 +383,9 @@ fun TestBorrow::test1(): TestBorrow::R { # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 7: $t8 := move($t0) - # moved_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t8) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t8))}, Reference($t6) -> {(.x (u64), Reference($t5))} + # live_nodes: LocalRoot($t8) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 8: return $t8 } @@ -434,7 +434,6 @@ fun TestBorrow::test10($t0|b: bool): TestBorrow::R { # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 9: $t2 := TestBorrow::test9($t0, $t6) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 10: goto 13 @@ -447,29 +446,24 @@ fun TestBorrow::test10($t0|b: bool): TestBorrow::R { # borrows_from: Reference($t2) -> {(@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 12: destroy($t6) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 13: label L3 # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 14: $t8 := 0 # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 15: write_ref($t2, $t8) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 16: $t9 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), Reference($t6) - # borrowed_by: LocalRoot($t9) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} - # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t9))}, Reference($t7) -> {(.x (u64), Reference($t6))} + # live_nodes: LocalRoot($t0), LocalRoot($t9) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.y (u64), Reference($t2)), (.x (u64)/@, Reference($t2)), (.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(.y (u64), Reference($t6)), (.x (u64)/@, Reference($t6)), (@, Reference($t7))}, Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(.x (u64), Reference($t6))} 17: return $t9 # live_nodes: LocalRoot($t0), Reference($t2), Reference($t6), Reference($t7) # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6))}, Reference($t6) -> {(.x (u64), Reference($t7))}, Reference($t7) -> {(@, Reference($t2))} @@ -554,9 +548,9 @@ fun TestBorrow::test4(): TestBorrow::R { # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))} # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))} 6: $t6 := move($t0) - # moved_nodes: LocalRoot($t0) - # borrowed_by: LocalRoot($t6) -> {(@, Reference($t4))} - # borrows_from: Reference($t4) -> {(@, LocalRoot($t6))} + # live_nodes: LocalRoot($t6) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t4))} + # borrows_from: Reference($t4) -> {(@, LocalRoot($t0))} 7: return $t6 } @@ -597,22 +591,19 @@ fun TestBorrow::test6(): TestBorrow::R { # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))} 4: $t6 := TestBorrow::test5($t5) # live_nodes: Reference($t6) - # moved_nodes: Reference($t5) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 5: $t7 := 0 # live_nodes: Reference($t6) - # moved_nodes: Reference($t5) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 6: TestBorrow::test2($t6, $t7) - # moved_nodes: Reference($t5) # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 7: $t8 := move($t0) - # moved_nodes: LocalRoot($t0), Reference($t5) - # borrowed_by: LocalRoot($t8) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t8))}, Reference($t6) -> {(.x (u64), Reference($t5))} + # live_nodes: LocalRoot($t8) + # borrowed_by: LocalRoot($t0) -> {(@, Reference($t5))}, Reference($t5) -> {(.x (u64), Reference($t6))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t0))}, Reference($t6) -> {(.x (u64), Reference($t5))} 8: return $t8 } diff --git a/language/move-prover/bytecode/tests/borrow_strong/mut_ref.exp b/language/move-prover/bytecode/tests/borrow_strong/mut_ref.exp index 8c61c9bd28..17a94d54f9 100644 --- a/language/move-prover/bytecode/tests/borrow_strong/mut_ref.exp +++ b/language/move-prover/bytecode/tests/borrow_strong/mut_ref.exp @@ -518,10 +518,9 @@ public fun vector::singleton<#0>($t0|e: #0): vector<#0> { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 3: $t3 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t2))} - # borrows_from: Reference($t2) -> {(@, LocalRoot($t3))} + # live_nodes: LocalRoot($t0), LocalRoot($t3) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t2))} + # borrows_from: Reference($t2) -> {(@, LocalRoot($t1))} 4: return $t3 } @@ -560,24 +559,20 @@ fun TestMutRef::call_return_ref_different_path($t0|b: bool): TestMutRef::N { # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))} 5: $t7 := TestMutRef::return_ref_different_path($t0, $t6) # live_nodes: LocalRoot($t0), Reference($t7) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t7)), (.t (TestMutRef::T)/.value (u64), Reference($t7))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(.value (u64), Reference($t6)), (.t (TestMutRef::T)/.value (u64), Reference($t6))} 6: $t8 := 5 # live_nodes: LocalRoot($t0), Reference($t7) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t7)), (.t (TestMutRef::T)/.value (u64), Reference($t7))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(.value (u64), Reference($t6)), (.t (TestMutRef::T)/.value (u64), Reference($t6))} 7: write_ref($t7, $t8) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t7)), (.t (TestMutRef::T)/.value (u64), Reference($t7))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(.value (u64), Reference($t6)), (.t (TestMutRef::T)/.value (u64), Reference($t6))} 8: $t9 := move($t2) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t2), Reference($t6) - # borrowed_by: LocalRoot($t9) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t7)), (.t (TestMutRef::T)/.value (u64), Reference($t7))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t9))}, Reference($t7) -> {(.value (u64), Reference($t6)), (.t (TestMutRef::T)/.value (u64), Reference($t6))} + # live_nodes: LocalRoot($t0), LocalRoot($t9) + # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t7)), (.t (TestMutRef::T)/.value (u64), Reference($t7))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(.value (u64), Reference($t6)), (.t (TestMutRef::T)/.value (u64), Reference($t6))} 9: return $t9 } @@ -628,40 +623,33 @@ fun TestMutRef::call_return_ref_different_path_vec($t0|b: bool): TestMutRef::V { # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))} 8: $t10 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))} + # live_nodes: LocalRoot($t0), LocalRoot($t10) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))} 9: $t4 := pack TestMutRef::V($t10, $t5) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))} + # live_nodes: LocalRoot($t0), LocalRoot($t10) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))} 10: $t11 := borrow_local($t4) - # live_nodes: LocalRoot($t0), Reference($t11) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t11))}, LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))}, Reference($t11) -> {(@, LocalRoot($t4))} + # live_nodes: LocalRoot($t0), LocalRoot($t10), Reference($t11) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t4) -> {(@, Reference($t11))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t11) -> {(@, LocalRoot($t4))} 11: $t12 := TestMutRef::return_ref_different_path_vec($t0, $t11) - # live_nodes: LocalRoot($t0), Reference($t12) - # moved_nodes: LocalRoot($t1), Reference($t11) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t11))}, LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} + # live_nodes: LocalRoot($t0), LocalRoot($t10), Reference($t12) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t4) -> {(@, Reference($t11))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} 12: $t13 := 5 - # live_nodes: LocalRoot($t0), Reference($t12) - # moved_nodes: LocalRoot($t1), Reference($t11) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t11))}, LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} + # live_nodes: LocalRoot($t0), LocalRoot($t10), Reference($t12) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t4) -> {(@, Reference($t11))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} 13: write_ref($t12, $t13) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), Reference($t11) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t11))}, LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} + # live_nodes: LocalRoot($t0), LocalRoot($t10) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t4) -> {(@, Reference($t11))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} 14: $t14 := move($t4) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t4), Reference($t11) - # borrowed_by: LocalRoot($t10) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t14) -> {(@, Reference($t11))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t8) -> {(@, LocalRoot($t10))}, Reference($t11) -> {(@, LocalRoot($t14))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} + # live_nodes: LocalRoot($t0), LocalRoot($t10), LocalRoot($t14) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t6)), (@, Reference($t8))}, LocalRoot($t4) -> {(@, Reference($t11))}, Reference($t11) -> {(.is (vector)/[], Reference($t12))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t1))}, Reference($t8) -> {(@, LocalRoot($t1))}, Reference($t11) -> {(@, LocalRoot($t4))}, Reference($t12) -> {(.is (vector)/[], Reference($t11))} 15: return $t14 } @@ -750,45 +738,37 @@ fun TestMutRef::call_return_ref_different_path_vec2($t0|b: bool): TestMutRef::V # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 16: $t15 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} + # live_nodes: LocalRoot($t0), LocalRoot($t15) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 17: $t16 := move($t3) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 18: $t4 := pack TestMutRef::V($t15, $t16) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 19: $t17 := borrow_local($t4) - # live_nodes: LocalRoot($t0), Reference($t17) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t17) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))} 20: $t18 := TestMutRef::return_ref_different_path_vec2($t0, $t17) - # live_nodes: LocalRoot($t0), Reference($t18) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t18) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 21: $t19 := 5 - # live_nodes: LocalRoot($t0), Reference($t18) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t18) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 22: write_ref($t18, $t19) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 23: $t20 := move($t4) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), LocalRoot($t4), Reference($t17) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t20) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t20))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), LocalRoot($t20) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 24: return $t20 } @@ -877,45 +857,37 @@ fun TestMutRef::call_return_ref_different_path_vec2_incorrect($t0|b: bool): Test # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 16: $t15 := move($t1) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} + # live_nodes: LocalRoot($t0), LocalRoot($t15) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 17: $t16 := move($t3) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 18: $t4 := pack TestMutRef::V($t15, $t16) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))} 19: $t17 := borrow_local($t4) - # live_nodes: LocalRoot($t0), Reference($t17) - # moved_nodes: LocalRoot($t1), LocalRoot($t3) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t17) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))} 20: $t18 := TestMutRef::return_ref_different_path_vec2($t0, $t17) - # live_nodes: LocalRoot($t0), Reference($t18) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t18) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 21: $t19 := 0 - # live_nodes: LocalRoot($t0), Reference($t18) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), Reference($t18) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 22: write_ref($t18, $t19) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), Reference($t17) - # borrowed_by: LocalRoot($t4) -> {(@, Reference($t17))}, LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 23: $t20 := move($t4) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t1), LocalRoot($t3), LocalRoot($t4), Reference($t17) - # borrowed_by: LocalRoot($t15) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t16) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t20) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} - # borrows_from: Reference($t5) -> {(@, LocalRoot($t15))}, Reference($t7) -> {(@, LocalRoot($t15))}, Reference($t9) -> {(@, LocalRoot($t16))}, Reference($t12) -> {(@, LocalRoot($t16))}, Reference($t17) -> {(@, LocalRoot($t20))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} + # live_nodes: LocalRoot($t0), LocalRoot($t15), LocalRoot($t16), LocalRoot($t20) + # borrowed_by: LocalRoot($t1) -> {(@, Reference($t5)), (@, Reference($t7))}, LocalRoot($t3) -> {(@, Reference($t9)), (@, Reference($t12))}, LocalRoot($t4) -> {(@, Reference($t17))}, Reference($t17) -> {(.is (vector)/[], Reference($t18)), (.ts (vector)/[]/.value (u64), Reference($t18))} + # borrows_from: Reference($t5) -> {(@, LocalRoot($t1))}, Reference($t7) -> {(@, LocalRoot($t1))}, Reference($t9) -> {(@, LocalRoot($t3))}, Reference($t12) -> {(@, LocalRoot($t3))}, Reference($t17) -> {(@, LocalRoot($t4))}, Reference($t18) -> {(.is (vector)/[], Reference($t17)), (.ts (vector)/[]/.value (u64), Reference($t17))} 24: return $t20 } @@ -952,29 +924,24 @@ fun TestMutRef::call_return_ref_different_root($t0|b: bool): (TestMutRef::T, Tes # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))} 6: $t8 := TestMutRef::return_ref_different_root($t0, $t6, $t7) # live_nodes: LocalRoot($t0), Reference($t8) - # moved_nodes: Reference($t6), Reference($t7) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, LocalRoot($t3) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} 7: $t9 := 5 # live_nodes: LocalRoot($t0), Reference($t8) - # moved_nodes: Reference($t6), Reference($t7) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, LocalRoot($t3) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} 8: write_ref($t8, $t9) # live_nodes: LocalRoot($t0) - # moved_nodes: Reference($t6), Reference($t7) # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, LocalRoot($t3) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} 9: $t10 := move($t2) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t2), Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t3) -> {(@, Reference($t7))}, LocalRoot($t10) -> {(@, Reference($t6))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} + # live_nodes: LocalRoot($t0), LocalRoot($t10) + # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, LocalRoot($t3) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} 10: $t11 := move($t3) - # live_nodes: LocalRoot($t0) - # moved_nodes: LocalRoot($t2), LocalRoot($t3), Reference($t6), Reference($t7) - # borrowed_by: LocalRoot($t10) -> {(@, Reference($t6))}, LocalRoot($t11) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} - # borrows_from: Reference($t6) -> {(@, LocalRoot($t10))}, Reference($t7) -> {(@, LocalRoot($t11))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} + # live_nodes: LocalRoot($t0), LocalRoot($t10), LocalRoot($t11) + # borrowed_by: LocalRoot($t2) -> {(@, Reference($t6))}, LocalRoot($t3) -> {(@, Reference($t7))}, Reference($t6) -> {(.value (u64), Reference($t8))}, Reference($t7) -> {(.value (u64), Reference($t8))} + # borrows_from: Reference($t6) -> {(@, LocalRoot($t2))}, Reference($t7) -> {(@, LocalRoot($t3))}, Reference($t8) -> {(.value (u64), Reference($t6)), (.value (u64), Reference($t7))} 11: return ($t10, $t11) } @@ -1038,7 +1005,6 @@ fun TestMutRef::return_ref_different_path_vec($t0|b: bool, $t1|x: &mut TestMutRe # borrows_from: Reference($t3) -> {(.is (vector), Reference($t1))} 4: $t2 := vector::borrow_mut($t3, $t4) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3))}, Reference($t3) -> {([], Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3))}, Reference($t3) -> {(.is (vector), Reference($t1))} 5: goto 10 @@ -1055,17 +1021,14 @@ fun TestMutRef::return_ref_different_path_vec($t0|b: bool, $t1|x: &mut TestMutRe # borrows_from: Reference($t5) -> {(.is (vector), Reference($t1))} 9: $t2 := vector::borrow_mut($t5, $t6) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.is (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), ([], Reference($t5))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.is (vector), Reference($t1))} 10: label L3 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.is (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), ([], Reference($t5))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.is (vector), Reference($t1))} 11: trace_local[x]($t1) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.is (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), ([], Reference($t5))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.is (vector), Reference($t1))} 12: return $t2 @@ -1095,7 +1058,6 @@ fun TestMutRef::return_ref_different_path_vec2($t0|b: bool, $t1|x: &mut TestMutR # borrows_from: Reference($t3) -> {(.is (vector), Reference($t1))} 4: $t2 := vector::borrow_mut($t3, $t4) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3))}, Reference($t3) -> {([], Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3))}, Reference($t3) -> {(.is (vector), Reference($t1))} 5: goto 11 @@ -1112,22 +1074,18 @@ fun TestMutRef::return_ref_different_path_vec2($t0|b: bool, $t1|x: &mut TestMutR # borrows_from: Reference($t5) -> {(.ts (vector), Reference($t1))} 9: $t7 := vector::borrow_mut($t5, $t6) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t7) - # moved_nodes: Reference($t5) # borrowed_by: Reference($t1) -> {(.ts (vector), Reference($t5))}, Reference($t5) -> {([], Reference($t7))} # borrows_from: Reference($t5) -> {(.ts (vector), Reference($t1))}, Reference($t7) -> {([], Reference($t5))} 10: $t2 := borrow_field.value($t7) # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.ts (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t7))}, Reference($t7) -> {(.value (u64), Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), (.value (u64), Reference($t7))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.ts (vector), Reference($t1))}, Reference($t7) -> {([], Reference($t5))} 11: label L3 # live_nodes: LocalRoot($t0), Reference($t1), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.ts (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t7))}, Reference($t7) -> {(.value (u64), Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), (.value (u64), Reference($t7))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.ts (vector), Reference($t1))}, Reference($t7) -> {([], Reference($t5))} 12: trace_local[x]($t1) # live_nodes: LocalRoot($t0), Reference($t2) - # moved_nodes: Reference($t3), Reference($t5) # borrowed_by: Reference($t1) -> {(.is (vector), Reference($t3)), (.ts (vector), Reference($t5))}, Reference($t3) -> {([], Reference($t2))}, Reference($t5) -> {([], Reference($t7))}, Reference($t7) -> {(.value (u64), Reference($t2))} # borrows_from: Reference($t2) -> {([], Reference($t3)), (.value (u64), Reference($t7))}, Reference($t3) -> {(.is (vector), Reference($t1))}, Reference($t5) -> {(.ts (vector), Reference($t1))}, Reference($t7) -> {([], Reference($t5))} 13: return $t2 diff --git a/language/move-prover/tests/sources/regression/moved_local_with_refs.move b/language/move-prover/tests/sources/regression/moved_local_with_refs.move new file mode 100644 index 0000000000..2bc16f0613 --- /dev/null +++ b/language/move-prover/tests/sources/regression/moved_local_with_refs.move @@ -0,0 +1,33 @@ +module 0x42::MovedLocalWithRefs { + use std::vector; + + struct S has drop { + x: u64, + } + + fun moved_local_in_loop(length: u64, limit: u64): vector { + let v = vector::empty(); + let i = 0; + while ({ + spec { + invariant i <= length; + invariant len(v) == i; + invariant forall k in 0..i: v[k].x <= limit; + }; + (i < length) + }) { + let s = S { x : 100 }; + if (s.x >= limit) { + s.x = limit; + }; + vector::push_back(&mut v, s); + i = i + 1; + }; + v + } + + spec moved_local_in_loop { + ensures len(result) == length; + ensures forall e in result: e.x <= limit; + } +} From 320de8f81d831b0e5453e44ec6b4832ff87bfba3 Mon Sep 17 00:00:00 2001 From: Wolfgang Grieskamp Date: Wed, 3 Aug 2022 18:42:23 -0700 Subject: [PATCH 031/169] [vm] Invalidate and flush code loader cache (#334) * [vm] Invalidate and auto-flush code loader cache This is a hack to workaround well-known issues with the VMs code loader cache. This cache is not designed to support module upgrade or deletion. This leads to situations where the cache does not reflect the state of storage: 1. On module upgrade, the upgraded module is in storage, but the old one still in the cache. 2. On an abandoned code publishing transaction, the cache may contain a module which was never committed to storage by the adapter. The solution is to add a flag to `Loader` marking it as 'invalidated'. For scenario (1), the VM sets the flag itself. For scenario (2), a public API allows the adapter to set the flag. If the cache invalidated, it can (and must) still be used until the end of the session. This is because during session execution, data might have been extracted which indirectly refers to the current cache (e.g. `CachedStructIndex`). Rather, when a *new* session is created, the VM will check the state of loader and flush it if needed. Note that this solution implies no concurrent excution of sessions. * [fixup] Addressing reviewer comments * [doc] Documentaedxc the `Loader.invalidated` flag better to capture the nature of this short time hack Co-authored-by: Wolfgang Grieskamp --- language/move-vm/runtime/src/loader.rs | 44 +++++++++++++++++++++++++ language/move-vm/runtime/src/move_vm.rs | 15 +++++++++ language/move-vm/runtime/src/runtime.rs | 19 ++++++++--- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/language/move-vm/runtime/src/loader.rs b/language/move-vm/runtime/src/loader.rs index 6e582e8c61..1b894ea0d7 100644 --- a/language/move-vm/runtime/src/loader.rs +++ b/language/move-vm/runtime/src/loader.rs @@ -441,6 +441,33 @@ pub(crate) struct Loader { module_cache: RwLock, type_cache: RwLock, natives: NativeFunctions, + + // The below field supports a hack to workaround well-known issues with the + // loader cache. This cache is not designed to support module upgrade or deletion. + // This leads to situations where the cache does not reflect the state of storage: + // + // 1. On module upgrade, the upgraded module is in storage, but the old one still in the cache. + // 2. On an abandoned code publishing transaction, the cache may contain a module which was + // never committed to storage by the adapter. + // + // The solution is to add a flag to Loader marking it as 'invalidated'. For scenario (1), + // the VM sets the flag itself. For scenario (2), a public API allows the adapter to set + // the flag. + // + // If the cache is invalidated, it can (and must) still be used until there are no more + // sessions alive which are derived from a VM with this loader. This is because there are + // internal data structures derived from the loader which can become inconsistent. Therefore + // the adapter must explicitly call a function to flush the invalidated loader. + // + // This code (the loader) needs a complete refactoring. The new loader should + // + // - support upgrade and deletion of modules, while still preserving max cache lookup + // performance. This is essential for a cache like this in a multi-tenant execution + // environment. + // - should delegate lifetime ownership to the adapter. Code loading (including verification) + // is a major execution bottleneck. We should be able to reuse a cache for the lifetime of + // the adapter/node, not just a VM or even session (as effectively today). + invalidated: RwLock, } impl Loader { @@ -450,9 +477,26 @@ impl Loader { module_cache: RwLock::new(ModuleCache::new()), type_cache: RwLock::new(TypeCache::new()), natives, + invalidated: RwLock::new(false), } } + /// Flush this cache if it is marked as invalidated. + pub(crate) fn flush_if_invalidated(&self) { + let mut invalidated = self.invalidated.write(); + if *invalidated { + *self.scripts.write() = ScriptCache::new(); + *self.module_cache.write() = ModuleCache::new(); + *self.type_cache.write() = TypeCache::new(); + *invalidated = false; + } + } + + /// Mark this cache as invalidated. + pub(crate) fn mark_as_invalid(&self) { + *self.invalidated.write() = true; + } + // // Script verification and loading // diff --git a/language/move-vm/runtime/src/move_vm.rs b/language/move-vm/runtime/src/move_vm.rs index 4127164a48..b8200cb7d4 100644 --- a/language/move-vm/runtime/src/move_vm.rs +++ b/language/move-vm/runtime/src/move_vm.rs @@ -71,4 +71,19 @@ impl MoveVM { ) .map(|arc_module| arc_module.arc_module()) } + + /// Allows the adapter to announce to the VM that the code loading cache should be considered + /// outdated. This can happen if the adapter executed a particular code publishing transaction + /// but decided to not commit the result to the data store. Because the code cache currently + /// does not support deletion, the cache will, incorrectly, still contain this module. + pub fn mark_loader_cache_as_invalid(&self) { + self.runtime.mark_loader_cache_as_invalid() + } + + /// If the loader cache has been invalidated (either by the above call or by internal logic) + /// flush it so it is valid again. Notice that should only be called if there are no + /// outstanding sessions created from this VM. + pub fn flush_loader_cache_if_invalidated(&self) { + self.runtime.flush_loader_cache_if_invalidated() + } } diff --git a/language/move-vm/runtime/src/runtime.rs b/language/move-vm/runtime/src/runtime.rs index 9d299a8abb..36bd358999 100644 --- a/language/move-vm/runtime/src/runtime.rs +++ b/language/move-vm/runtime/src/runtime.rs @@ -49,12 +49,16 @@ impl VMRuntime { }) } + pub(crate) fn mark_loader_cache_as_invalid(&self) { + self.loader.mark_as_invalid() + } + + pub(crate) fn flush_loader_cache_if_invalidated(&self) { + self.loader.flush_if_invalidated() + } + pub fn new_session<'r, S: MoveResolver>(&self, remote: &'r S) -> Session<'r, '_, S> { - Session { - runtime: self, - data_cache: TransactionDataCache::new(remote, &self.loader), - native_extensions: NativeContextExtensions::default(), - } + self.new_session_with_extensions(remote, NativeContextExtensions::default()) } pub fn new_session_with_extensions<'r, S: MoveResolver>( @@ -193,6 +197,11 @@ impl VMRuntime { // All modules verified, publish them to data cache for (module, blob) in compiled_modules.into_iter().zip(modules.into_iter()) { + if data_store.exists_module(&module.self_id())? { + // This is an upgrade, so invalidate the loader cache, which still contains the + // old module. + self.loader.mark_as_invalid(); + } data_store.publish_module(&module.self_id(), blob)?; } Ok(()) From ad0db1d3a88386fbd5f13517b29ca1cd0f72a519 Mon Sep 17 00:00:00 2001 From: gold experience <42137630+goldexperie@users.noreply.github.com> Date: Fri, 5 Aug 2022 00:18:17 +0700 Subject: [PATCH 032/169] [move-cli] Filter tests by module_name::test_name (#337) * Filter test by module_name::test_name * Fix lint error --- language/tools/move-unit-test/src/test_runner.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/language/tools/move-unit-test/src/test_runner.rs b/language/tools/move-unit-test/src/test_runner.rs index 547c7cd2a4..b2c6f0e8ab 100644 --- a/language/tools/move-unit-test/src/test_runner.rs +++ b/language/tools/move-unit-test/src/test_runner.rs @@ -210,7 +210,11 @@ impl TestRunner { let tests = std::mem::take(&mut module_test.tests); module_test.tests = tests .into_iter() - .filter(|(test_name, _)| test_name.as_str().contains(test_name_slice)) + .filter(|(test_name, _)| { + let full_name = + format!("{}::{}", module_id.name().as_str(), test_name.as_str()); + full_name.contains(test_name_slice) + }) .collect(); } } From cfd250087d09a4e2b6c7002709800d3c4deb4646 Mon Sep 17 00:00:00 2001 From: "Kaiwen (Chloe) Chen" <35128156+ckaiwxm@users.noreply.github.com> Date: Thu, 4 Aug 2022 18:32:47 -0400 Subject: [PATCH 033/169] [unit-test] Add unit test for choice operator (#343) --- .../tests/concrete_check/choice.exp | 39 ++++++++++++------- .../tests/concrete_check/choice.move | 22 +++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp index e7da95feb6..c32e377b3f 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.exp @@ -1,6 +1,8 @@ Running Move unit tests [ FAIL ] 0x2::A::simple_number_min_range_failure [ FAIL ] 0x2::A::simple_number_range_failure +[ PASS ] 0x2::A::unroll_address_success +[ FAIL ] 0x2::A::unroll_address_unsatisfied_predicate [ FAIL ] 0x2::A::vector_choose_min_unsatisfied_predicate [ PASS ] 0x2::A::vector_choose_success [ FAIL ] 0x2::A::vector_choose_unsatisfied_predicate @@ -11,15 +13,15 @@ Failures in 0x2::A: ┌── simple_number_min_range_failure ────── │ error: failed to evaluate expression: enumeration of a non-address type domain is not supported -│ ┌─ tests/concrete_check/choice.move:56:42 +│ ┌─ tests/concrete_check/choice.move:78:42 │ │ -│ 56 │ ensures result <= (choose min x: u64 where x >= 4); +│ 78 │ ensures result <= (choose min x: u64 where x >= 4); │ │ ^^^ │ │ error: failed to evaluate expression: unexpected error code -│ ┌─ tests/concrete_check/choice.move:56:17 +│ ┌─ tests/concrete_check/choice.move:78:17 │ │ -│ 56 │ ensures result <= (choose min x: u64 where x >= 4); +│ 78 │ ensures result <= (choose min x: u64 where x >= 4); │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ │ @@ -28,26 +30,37 @@ Failures in 0x2::A: ┌── simple_number_range_failure ────── │ error: failed to evaluate expression: enumeration of a non-address type domain is not supported -│ ┌─ tests/concrete_check/choice.move:49:38 +│ ┌─ tests/concrete_check/choice.move:71:38 │ │ -│ 49 │ ensures result <= (choose x: u64 where x >= 4); +│ 71 │ ensures result <= (choose x: u64 where x >= 4); │ │ ^^^ │ │ error: failed to evaluate expression: unexpected error code -│ ┌─ tests/concrete_check/choice.move:49:17 +│ ┌─ tests/concrete_check/choice.move:71:17 │ │ -│ 49 │ ensures result <= (choose x: u64 where x >= 4); +│ 71 │ ensures result <= (choose x: u64 where x >= 4); │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ │ └────────────────── +┌── unroll_address_unsatisfied_predicate ────── +│ error: failed to evaluate expression: choose fails to satisfy a predicate +│ ┌─ tests/concrete_check/choice.move:23:51 +│ │ +│ 23 │ let post choice = choose a: address where !exists(a); +│ │ ^^^^^^^^^^^^^ +│ +│ +└────────────────── + + ┌── vector_choose_min_unsatisfied_predicate ────── │ error: failed to evaluate expression: choose min fails to satisfy a predicate -│ ┌─ tests/concrete_check/choice.move:42:68 +│ ┌─ tests/concrete_check/choice.move:64:68 │ │ -│ 42 │ let post choice_min = choose min i in 0..len(result) where result[i] == 3; +│ 64 │ let post choice_min = choose min i in 0..len(result) where result[i] == 3; │ │ ^^^^^^^^^^^^^^ │ │ @@ -56,12 +69,12 @@ Failures in 0x2::A: ┌── vector_choose_unsatisfied_predicate ────── │ error: failed to evaluate expression: choose fails to satisfy a predicate -│ ┌─ tests/concrete_check/choice.move:29:60 +│ ┌─ tests/concrete_check/choice.move:51:60 │ │ -│ 29 │ let post choice = choose i in 0..len(result) where result[i] == 3; +│ 51 │ let post choice = choose i in 0..len(result) where result[i] == 3; │ │ ^^^^^^^^^^^^^^ │ │ └────────────────── -Test result: FAILED. Total tests: 5; passed: 1; failed: 4 +Test result: FAILED. Total tests: 7; passed: 2; failed: 5 diff --git a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move index 030bfa1bfc..096726d0cf 100644 --- a/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move +++ b/language/move-prover/interpreter-testsuite/tests/concrete_check/choice.move @@ -1,6 +1,28 @@ module 0x2::A { use std::vector; + struct R has key { i: u64 } + + #[test(a=@0x2)] + public fun unroll_address_success(a: &signer) { + let r = R{i: 1}; + move_to(a, r); + } + + spec unroll_address_success { + let post choice = choose a: address where exists(a) && global(a).i == 1; + } + + #[test(a=@0x2)] + public fun unroll_address_unsatisfied_predicate(a: &signer) { + let r = R{i: 1}; + move_to(a, r); + } + + spec unroll_address_unsatisfied_predicate { + let post choice = choose a: address where !exists(a); + } + #[test] public fun vector_choose_success(): vector { let v = vector::empty(); From 74bab15c9a1d3c22ba86966bbd6061a323475281 Mon Sep 17 00:00:00 2001 From: Zoey <101599447+zoey-t@users.noreply.github.com> Date: Thu, 4 Aug 2022 19:19:34 -0700 Subject: [PATCH 034/169] fix error lib. (#344) --- .../experimental/coin-swap/sources/CoinSwap.move | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/language/documentation/examples/experimental/coin-swap/sources/CoinSwap.move b/language/documentation/examples/experimental/coin-swap/sources/CoinSwap.move index 6d92a57a5b..e97b7112ad 100644 --- a/language/documentation/examples/experimental/coin-swap/sources/CoinSwap.move +++ b/language/documentation/examples/experimental/coin-swap/sources/CoinSwap.move @@ -1,6 +1,6 @@ module CoinSwap::CoinSwap { use std::signer; - use std::errors; + use std::error; use BasicCoin::BasicCoin; use CoinSwap::PoolToken; @@ -27,8 +27,8 @@ module CoinSwap::CoinSwap { // TODO: Alternatively, `struct LiquidityPool` could be refactored to actually hold the coin (e.g., coin1: CoinType1). BasicCoin::publish_balance(coinswap); BasicCoin::publish_balance(coinswap); - assert!(signer::address_of(coinswap) == @CoinSwap, errors::invalid_argument(ECOINSWAP_ADDRESS)); - assert!(!exists>(signer::address_of(coinswap)), errors::already_published(EPOOL)); + assert!(signer::address_of(coinswap) == @CoinSwap, error::invalid_argument(ECOINSWAP_ADDRESS)); + assert!(!exists>(signer::address_of(coinswap)), error::already_exists(EPOOL)); move_to(coinswap, LiquidityPool{coin1, coin2, share}); // Transfer the initial liquidity of CoinType1 and CoinType2 to the pool under @CoinSwap. @@ -53,8 +53,8 @@ module CoinSwap::CoinSwap { witness1: CoinType1, witness2: CoinType2 ) acquires LiquidityPool { - assert!(signer::address_of(coinswap) == @CoinSwap, errors::invalid_argument(ECOINSWAP_ADDRESS)); - assert!(exists>(signer::address_of(coinswap)), errors::not_published(EPOOL)); + assert!(signer::address_of(coinswap) == @CoinSwap, error::invalid_argument(ECOINSWAP_ADDRESS)); + assert!(exists>(signer::address_of(coinswap)), error::not_found(EPOOL)); let pool = borrow_global_mut>(signer::address_of(coinswap)); let coin2 = get_input_price(coin1, pool.coin1, pool.coin2); pool.coin1 = pool.coin1 + coin1; From e97dc204943776e80a16255432ee4e92c4e08652 Mon Sep 17 00:00:00 2001 From: Wolfgang Grieskamp Date: Thu, 4 Aug 2022 19:20:39 -0700 Subject: [PATCH 035/169] [vm] Add ability for adapter to observe module loader cache hits (#341) * [vm] Add ability for adapter to observe module loader cache hits If a VM is used to execute multiple sessions, the adapter is not cabable to see which modules have been loaded by a given transaction, because modules are cached internaly by the VM, and no call back to the adapters data store happens. This PR adds a small change which allows the adapter to read out this information, roughly as follows: ``` let vm = MoveVM::new(); let session = vm.new_session(); <> let cache_hits = vm.get_and_clear_module_cacheHits(); let used_modules = cache_hits + modules_read_from_storage() // next session starts with 0 cache hits let session = vm.new_session(); ... ``` * [fixup] Return transtive closure of dependencies because this is the 'logical' cache hit --- language/move-vm/runtime/src/loader.rs | 35 +++++++++++++++++++++++++ language/move-vm/runtime/src/move_vm.rs | 16 ++++++++--- language/move-vm/runtime/src/runtime.rs | 8 ------ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/language/move-vm/runtime/src/loader.rs b/language/move-vm/runtime/src/loader.rs index 1b894ea0d7..62906f0f93 100644 --- a/language/move-vm/runtime/src/loader.rs +++ b/language/move-vm/runtime/src/loader.rs @@ -468,6 +468,11 @@ pub(crate) struct Loader { // is a major execution bottleneck. We should be able to reuse a cache for the lifetime of // the adapter/node, not just a VM or even session (as effectively today). invalidated: RwLock, + + // Collects the cache hits on module loads. This information can be read and reset by + // an adapter to reason about read/write conflicts of code publishing transactions and + // other transactions. + module_cache_hits: RwLock>, } impl Loader { @@ -478,6 +483,35 @@ impl Loader { type_cache: RwLock::new(TypeCache::new()), natives, invalidated: RwLock::new(false), + module_cache_hits: RwLock::new(BTreeSet::new()), + } + } + + /// Gets and clears module cache hits. A cache hit may also be caused indirectly by + /// loading a function or a type. This not only returns the direct hit, but also + /// indirect ones, that is all dependencies. + pub(crate) fn get_and_clear_module_cache_hits(&self) -> BTreeSet { + let mut result = BTreeSet::new(); + let hits: BTreeSet = std::mem::take(&mut self.module_cache_hits.write()); + for id in hits { + self.transitive_dep_closure(&id, &mut result) + } + result + } + + fn transitive_dep_closure(&self, id: &ModuleId, visited: &mut BTreeSet) { + if !visited.insert(id.clone()) { + return; + } + let entry = self.module_cache.read(); + for dep in entry + .modules + .get(id) + .unwrap() + .module + .immediate_dependencies() + { + self.transitive_dep_closure(&dep, visited) } } @@ -888,6 +922,7 @@ impl Loader { ) -> VMResult> { // if the module is already in the code cache, load the cached version if let Some(cached) = self.module_cache.read().module_at(id) { + self.module_cache_hits.write().insert(id.clone()); return Ok(cached); } diff --git a/language/move-vm/runtime/src/move_vm.rs b/language/move-vm/runtime/src/move_vm.rs index b8200cb7d4..f588f31fca 100644 --- a/language/move-vm/runtime/src/move_vm.rs +++ b/language/move-vm/runtime/src/move_vm.rs @@ -2,7 +2,7 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; +use std::{collections::BTreeSet, sync::Arc}; use crate::{ data_cache::TransactionDataCache, native_extensions::NativeContextExtensions, @@ -76,14 +76,24 @@ impl MoveVM { /// outdated. This can happen if the adapter executed a particular code publishing transaction /// but decided to not commit the result to the data store. Because the code cache currently /// does not support deletion, the cache will, incorrectly, still contain this module. + /// TODO: new loader architecture pub fn mark_loader_cache_as_invalid(&self) { - self.runtime.mark_loader_cache_as_invalid() + self.runtime.loader().mark_as_invalid() } /// If the loader cache has been invalidated (either by the above call or by internal logic) /// flush it so it is valid again. Notice that should only be called if there are no /// outstanding sessions created from this VM. + /// TODO: new loader architecture pub fn flush_loader_cache_if_invalidated(&self) { - self.runtime.flush_loader_cache_if_invalidated() + self.runtime.loader().flush_if_invalidated() + } + + /// Gets and clears module cache hits. This is hack which allows the adapter to see module + /// reads if executing multiple transactions in a VM. Without this, the adapter only sees + /// the first load of a module. + /// TODO: new loader architecture + pub fn get_and_clear_module_cache_hits(&self) -> BTreeSet { + self.runtime.loader().get_and_clear_module_cache_hits() } } diff --git a/language/move-vm/runtime/src/runtime.rs b/language/move-vm/runtime/src/runtime.rs index 36bd358999..2578593d81 100644 --- a/language/move-vm/runtime/src/runtime.rs +++ b/language/move-vm/runtime/src/runtime.rs @@ -49,14 +49,6 @@ impl VMRuntime { }) } - pub(crate) fn mark_loader_cache_as_invalid(&self) { - self.loader.mark_as_invalid() - } - - pub(crate) fn flush_loader_cache_if_invalidated(&self) { - self.loader.flush_if_invalidated() - } - pub fn new_session<'r, S: MoveResolver>(&self, remote: &'r S) -> Session<'r, '_, S> { self.new_session_with_extensions(remote, NativeContextExtensions::default()) } From f963939568ca796f4bf94dbb98d7c2cbc8cc21c3 Mon Sep 17 00:00:00 2001 From: Junkil Park Date: Fri, 5 Aug 2022 18:16:27 -0700 Subject: [PATCH 036/169] Added some missing native functions in Prover's prelude (#347) - Added some missing native function mock-ups in Prover's prelude - Need to revisit the new `guid` and `counter` functions because Prover has abstracted those out in verification. --- .../boogie-backend/src/prelude/native.bpl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/language/move-prover/boogie-backend/src/prelude/native.bpl b/language/move-prover/boogie-backend/src/prelude/native.bpl index a0a6724cf4..f0694357fe 100644 --- a/language/move-prover/boogie-backend/src/prelude/native.bpl +++ b/language/move-prover/boogie-backend/src/prelude/native.bpl @@ -246,6 +246,10 @@ procedure {:inline 2} {{Ext}}_table_new{{S}}() returns (v: {{Self}}) { v := EmptyTable(); } +procedure {:inline 2} {{Ext}}_table_destroy{{S}}(t: {{Self}}) { + // no-op +} + procedure {:inline 2} {{Ext}}_table_destroy_empty{{S}}(t: {{Self}}) { if (LenTable(t) != 0) { call $Abort($StdError(1/*INVALID_STATE*/, 102/*ENOT_EMPTY*/)); @@ -430,6 +434,18 @@ returns (res: $Mutation $1_event_EventHandle{{S}}) { res := handle_mut; } +procedure {:inline 1} $1_event_guid{{S}}(handle_ref: $1_event_EventHandle{{S}}) +returns (res: int) { + // TODO: temporarily mocked. The return type needs to be fixed. + res := 0; +} + +procedure {:inline 1} $1_event_counter{{S}}(handle_ref: $1_event_EventHandle{{S}}) +returns (res: int) { + // TODO: temporarily mocked. + res := 0; +} + procedure {:inline 1} $1_event_destroy_handle{{S}}(handle: $1_event_EventHandle{{S}}) { } From 7b24d06a27dc02d387b60b98c10a19b558a4d90d Mon Sep 17 00:00:00 2001 From: Meng Xu <72079339+meng-xu-cs@users.noreply.github.com> Date: Sat, 6 Aug 2022 00:43:10 -0400 Subject: [PATCH 037/169] [move-prover] fix field type instantiation in borrow edge (#350) --- language/move-prover/boogie-backend/src/bytecode_translator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/move-prover/boogie-backend/src/bytecode_translator.rs b/language/move-prover/boogie-backend/src/bytecode_translator.rs index a78b1fb304..8ccb0461ae 100644 --- a/language/move-prover/boogie-backend/src/bytecode_translator.rs +++ b/language/move-prover/boogie-backend/src/bytecode_translator.rs @@ -1611,7 +1611,7 @@ impl<'env> FunctionTranslator<'env> { let field_env = &struct_env.get_field_by_offset(*offset); let sel_fun = boogie_field_sel(field_env, &memory.inst); let new_dest = format!("{}({})", sel_fun, (*mk_dest)()); - let new_dest_ty = &self.inst(&field_env.get_type()); + let new_dest_ty = &field_env.get_type().instantiate(&memory.inst); let mut new_dest_needed = false; let new_src = self.translate_write_back_update( new_dest_ty, From 9169307db32266ca6c70a9bc8b1f91febef6c69f Mon Sep 17 00:00:00 2001 From: Wolfgang Grieskamp Date: Fri, 5 Aug 2022 22:51:28 -0700 Subject: [PATCH 038/169] [move-on-evm] Clarify in the readme that this is an experimental feature. (#349) --- language/evm/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/language/evm/README.md b/language/evm/README.md index 6baba04f3d..883e3bd883 100644 --- a/language/evm/README.md +++ b/language/evm/README.md @@ -1,5 +1,9 @@ # Move-on-EVM +> NOTE: this tree contains an experimental version of Move which runs on the EVM. The programming model is +> different from regular Move. The examples in this directory do not work with the usual Move +> tools and blockchains. + "Move-on-EVM" is a programming model in Move for EVM. In the current model, *each Move EVM contract has its own isolated address space*. This reflects the setup of the EVM most naturally, where storage between contracts cannot be shared apart from via accessor contract functions. Move EVM contracts use attributes to indicate the usage of structs for storage and events, and for functions to be callable from other contracts. It is expected that there is some codegen of Move from these attributes. For example, functions marked as `callable` have a generated API for cross-contract EVM call and delegate invocations. The module [Evm.move](./stdlib/sources/Evm.move) contains the API of a Move contract to the EVM. It encapsulates access to the transaction context and other EVM builtins This directory contains the following sub-directories: From 3c47a9543c0cf7c0e6f56af5b7d8eb34ccea75fe Mon Sep 17 00:00:00 2001 From: Deagler Date: Sat, 6 Aug 2022 13:30:47 -0600 Subject: [PATCH 039/169] [move-analyzer] Add Docstring rendering on-hover (#328) * [move-analyzer] Add docstring rendering for consts, structs, functions * [move-analyzer] Optimize docstring construction * [move-analyzer] Add rendering for docstrings across other modules * [move-analyzer] Fix M1.move tests * [move-analyzer] Add unit tests for docstring construction * [move-analyzer] Add integration tests for docstring construction * [move-analyzer] Add support for /** .. */ docstring comments * [move-analyzer] Update unit/integration tests to test asterix-based docstrings * [move-analyzer] Fix general PR comments * [move-analyzer] Improve extract_doc_string readability * [move-analyzer] Fix linter issues --- .gitignore | 1 + .../move-analyzer/editors/code/.eslintrc.json | 2 +- .../editors/code/src/commands/lsp_command.ts | 22 +- .../move-analyzer/editors/code/src/main.ts | 1 + .../code/tests/lsp-demo/sources/M2.move | 22 + .../code/tests/lsp-demo/sources/M3.move | 12 + .../editors/code/tests/lsp.test.ts | 79 ++++ language/move-analyzer/src/symbols.rs | 385 +++++++++++++++++- .../tests/symbols/sources/M6.move | 42 ++ .../tests/symbols/sources/M7.move | 13 + 10 files changed, 570 insertions(+), 9 deletions(-) create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/sources/M2.move create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/sources/M3.move create mode 100644 language/move-analyzer/tests/symbols/sources/M6.move create mode 100644 language/move-analyzer/tests/symbols/sources/M7.move diff --git a/.gitignore b/.gitignore index 13d3db1d03..124e0b7c75 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ **/target **/*.rs.bk .idea/ +**/.vscode # Ignore wallet mnemonic files used for deterministic key derivation *.mnemonic diff --git a/language/move-analyzer/editors/code/.eslintrc.json b/language/move-analyzer/editors/code/.eslintrc.json index 2238dc578b..a6a2d7351c 100644 --- a/language/move-analyzer/editors/code/.eslintrc.json +++ b/language/move-analyzer/editors/code/.eslintrc.json @@ -110,7 +110,7 @@ "max-len": [ "warn", { - "code": 100, + "code": 120, "ignoreUrls": true } ], diff --git a/language/move-analyzer/editors/code/src/commands/lsp_command.ts b/language/move-analyzer/editors/code/src/commands/lsp_command.ts index 0387d77d09..dbbda4af5e 100644 --- a/language/move-analyzer/editors/code/src/commands/lsp_command.ts +++ b/language/move-analyzer/editors/code/src/commands/lsp_command.ts @@ -3,7 +3,7 @@ import type { SymbolInformation, DocumentSymbol, } from 'vscode-languageclient'; -import { DocumentSymbolRequest } from 'vscode-languageclient'; +import { DocumentSymbolRequest, HoverRequest } from 'vscode-languageclient'; import type { Context } from '../context'; /** @@ -12,7 +12,7 @@ import type { Context } from '../context'; export async function textDocumentDocumentSymbol( context: Readonly, params: DocumentSymbolParams, - ) +) : Promise { const client = context.getClient(); if (client === undefined) { @@ -22,3 +22,21 @@ export async function textDocumentDocumentSymbol( // Send the request to the language client. return client.sendRequest(DocumentSymbolRequest.type, params); } + + +/** + * An LSP command textDocument/hover + */ +export async function textDocumentHover( + context: Readonly, + params: DocumentSymbolParams, +) + : Promise { + const client = context.getClient(); + if (client === undefined) { + return Promise.reject(new Error('No language client connected.')); + } + + // Send the request to the language client. + return client.sendRequest(HoverRequest.method, params); +} diff --git a/language/move-analyzer/editors/code/src/main.ts b/language/move-analyzer/editors/code/src/main.ts index 29edca6a59..a219035197 100644 --- a/language/move-analyzer/editors/code/src/main.ts +++ b/language/move-analyzer/editors/code/src/main.ts @@ -74,4 +74,5 @@ export async function activate(extensionContext: Readonly { Mocha.test('textDocument/documentSymbol', async () => { @@ -49,4 +50,82 @@ Mocha.suite('LSP', () => { assert.deepStrictEqual(syms[0]?.children[3].name, 'this_is_a_test'); assert.deepStrictEqual(syms[0]?.children[3]?.detail, '["test", "expected_failure"]'); }); + + Mocha.test('textDocument/hover for definition in the same module', async () => { + const ext = vscode.extensions.getExtension('move.move-analyzer'); + assert.ok(ext); + + await ext.activate(); // Synchronous waiting for activation to complete + + // 1. get workdir + const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; + + // 2. open doc + const docs = await vscode.workspace.openTextDocument( + path.join(workDir, 'sources/M2.move'), + ); + await vscode.window.showTextDocument(docs); + + // 3. execute command + const params: lc.HoverParams = { + textDocument: { + uri: docs.uri.toString(), + }, + position: { + line: 12, + character: 8, + }, + }; + + const hoverResult: lc.Hover | undefined = + await vscode.commands.executeCommand( + 'move-analyzer.textDocumentHover', + params, + ); + + assert.ok(hoverResult); + assert.deepStrictEqual((hoverResult.contents as MarkupContent).value, + // eslint-disable-next-line max-len + 'fun Symbols::M2::other_doc_struct(): Symbols::M3::OtherDocStruct\n\n\nThis is a multiline docstring\n\nThis docstring has empty lines.\n\nIt uses the ** format instead of ///\n\n'); + + }); + + Mocha.test('textDocument/hover for definition in an external module', async () => { + const ext = vscode.extensions.getExtension('move.move-analyzer'); + assert.ok(ext); + + await ext.activate(); // Synchronous waiting for activation to complete + + // 1. get workdir + const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; + + // 2. open doc + const docs = await vscode.workspace.openTextDocument( + path.join(workDir, 'sources/M2.move'), + ); + await vscode.window.showTextDocument(docs); + + // 3. execute command + const params: lc.HoverParams = { + textDocument: { + uri: docs.uri.toString(), + }, + position: { + line: 18, + character: 35, + }, + }; + + const hoverResult: lc.Hover | undefined = + await vscode.commands.executeCommand( + 'move-analyzer.textDocumentHover', + params, + ); + + + assert.ok(hoverResult); + assert.deepStrictEqual((hoverResult.contents as MarkupContent).value, + 'Symbols::M3::OtherDocStruct\n\nDocumented struct in another module\n'); + + }); }); diff --git a/language/move-analyzer/src/symbols.rs b/language/move-analyzer/src/symbols.rs index 10140a17c7..6a2adc5af5 100644 --- a/language/move-analyzer/src/symbols.rs +++ b/language/move-analyzer/src/symbols.rs @@ -147,6 +147,8 @@ pub struct UseDef { def_loc: DefLoc, /// Location of the type definition type_def_loc: Option, + /// Doc string for the relevant identifier/function + doc_string: String, } /// Definition of a struct field @@ -195,6 +197,8 @@ pub struct Symbolicator { files: SimpleFiles, /// A mapping from file hashes to file IDs (used to obtain source file locations) file_id_mapping: HashMap, + // A mapping from file IDs to a split vector of the lines in each file (used to build docstrings) + file_id_to_lines: HashMap>, /// Contains type params where relevant (e.g. when processing function definition) type_params: BTreeMap, /// Current processed module (always set before module processing starts) @@ -479,6 +483,7 @@ impl UseDef { use_name: &Symbol, use_type: IdentType, type_def_loc: Option, + doc_string: String, ) -> Self { let def_loc = DefLoc { fhash: def_fhash, @@ -501,6 +506,7 @@ impl UseDef { use_type, def_loc, type_def_loc, + doc_string, } } } @@ -582,11 +588,14 @@ impl Symbolicator { let source_files = &resolution_graph.file_sources(); let mut files = SimpleFiles::new(); let mut file_id_mapping = HashMap::new(); + let mut file_id_to_lines = HashMap::new(); let mut file_name_mapping = BTreeMap::new(); for (fhash, (fname, source)) in source_files { let id = files.add(*fname, source.clone()); file_id_mapping.insert(*fhash, id); file_name_mapping.insert(*fhash, *fname); + let lines: Vec = source.lines().map(String::from).collect(); + file_id_to_lines.insert(id, lines); } let build_plan = BuildPlan::create(resolution_graph)?; @@ -682,6 +691,7 @@ impl Symbolicator { mod_outer_defs, files, file_id_mapping, + file_id_to_lines, type_params: BTreeMap::new(), current_mod: None, }; @@ -770,6 +780,7 @@ impl Symbolicator { continue; } }; + structs.insert( *name, StructDef { @@ -860,6 +871,8 @@ impl Symbolicator { for (pos, name, fun) in &mod_def.functions { // enter self-definition for function name (unwrap safe - done when inserting def) let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); + let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); + let use_type = IdentType::FunctionType( self.current_mod.unwrap().value, *name, @@ -893,6 +906,7 @@ impl Symbolicator { name, use_type, ident_type_def, + doc_string, ), ); self.fun_symbols(fun, references, use_defs); @@ -901,6 +915,7 @@ impl Symbolicator { for (pos, name, c) in &mod_def.constants { // enter self-definition for const name (unwrap safe - done when inserting def) let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); + let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); let ident_type = IdentType::RegularType(c.signature.clone()); let ident_type_def = self.ident_type_def_loc(&ident_type); use_defs.insert( @@ -914,6 +929,7 @@ impl Symbolicator { name, ident_type, ident_type_def, + doc_string, ), ); } @@ -921,6 +937,7 @@ impl Symbolicator { for (pos, name, struct_def) in &mod_def.structs { // enter self-definition for struct name (unwrap safe - done when inserting def) let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); + let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); let ident_type = IdentType::RegularType(Self::create_struct_type( self.current_mod.unwrap(), StructName(sp(pos, *name)), @@ -939,6 +956,7 @@ impl Symbolicator { name, ident_type, ident_type_def, + doc_string, ), ); @@ -966,6 +984,7 @@ impl Symbolicator { let start = Self::get_start_loc(&fpos, &self.files, &self.file_id_mapping).unwrap(); let ident_type = IdentType::RegularType(t.clone()); let ident_type_def = self.ident_type_def_loc(&ident_type); + let doc_string = self.extract_doc_string(&start, &fpos.file_hash()); use_defs.insert( start.line, UseDef::new( @@ -977,6 +996,7 @@ impl Symbolicator { fname, ident_type, ident_type_def, + doc_string, ), ); } @@ -1051,6 +1071,74 @@ impl Symbolicator { get_loc(&pos.file_hash(), pos.start(), files, file_id_mapping) } + /// Extracts the docstring (/// or /** ... */) for a given definition by traversing up from the line definition + fn extract_doc_string(&self, name_start: &Position, file_hash: &FileHash) -> String { + let mut doc_string = String::new(); + let file_id = match self.file_id_mapping.get(file_hash) { + None => return doc_string, + Some(v) => v, + }; + + let file_lines = match self.file_id_to_lines.get(file_id) { + None => return doc_string, + Some(v) => v, + }; + + if name_start.line == 0 { + return doc_string; + } + + let mut iter = (name_start.line - 1) as usize; + let mut line_before = file_lines[iter].trim(); + + // Detect the two different types of docstrings + if line_before.starts_with("///") { + while let Some(stripped_line) = line_before.strip_prefix("///") { + doc_string = format!("{}\n{}", stripped_line.trim(), doc_string); + if iter == 0 { + break; + } + iter -= 1; + line_before = file_lines[iter].trim(); + } + } else if line_before.ends_with("*/") { + let mut doc_string_found = false; + line_before = file_lines[iter].strip_suffix("*/").unwrap_or("").trim(); + + // Loop condition is a safe guard. + while !doc_string_found { + // We found the start of the multi-line comment/docstring + if line_before.starts_with("/*") { + let is_doc = line_before.starts_with("/**") && !line_before.starts_with("/***"); + + // Invalid doc_string start prefix so return empty doc string. + if !is_doc { + return String::new(); + } + + line_before = line_before.strip_prefix("/**").unwrap_or("").trim(); + doc_string_found = true; + } + + doc_string = format!("{}\n{}", line_before, doc_string); + + if iter == 0 { + break; + } + + iter -= 1; + line_before = file_lines[iter].trim(); + } + + // No doc_string found - return String::new(); + if !doc_string_found { + return String::new(); + } + } + + doc_string + } + /// Get symbols for a sequence representing function body fn seq_item_symbols( &self, @@ -1479,6 +1567,8 @@ impl Symbolicator { Type_::Param(tp.clone()), )); let ident_type_def = self.ident_type_def_loc(&ident_type); + + let doc_string = self.extract_doc_string(&start, &fhash); use_defs.insert( start.line, UseDef::new( @@ -1490,6 +1580,7 @@ impl Symbolicator { &tname, ident_type, ident_type_def, + doc_string, ), ); let exists = tp_scope.insert(tname, DefLoc { fhash, start }); @@ -1549,18 +1640,22 @@ impl Symbolicator { |use_name, name_start, mod_defs| match mod_defs.constants.get(use_name) { Some(def_start) => { let ident_type = IdentType::RegularType(use_type.clone()); + let def_fhash = self.mod_outer_defs.get(&module_ident).unwrap().fhash; + let doc_string = self.extract_doc_string(def_start, &def_fhash); let ident_type_def = self.ident_type_def_loc(&ident_type); + use_defs.insert( name_start.line, UseDef::new( references, use_pos.file_hash(), name_start, - self.mod_outer_defs.get(&module_ident).unwrap().fhash, + def_fhash, *def_start, use_name, ident_type, ident_type_def, + doc_string, ), ); } @@ -1585,17 +1680,20 @@ impl Symbolicator { use_pos, |use_name, name_start, mod_defs| match mod_defs.functions.get(use_name) { Some(func_def) => { + let def_fhash = self.mod_outer_defs.get(&module_ident.value).unwrap().fhash; + let doc_string = self.extract_doc_string(&func_def.start, &def_fhash); use_defs.insert( name_start.line, UseDef::new( references, use_pos.file_hash(), name_start, - self.mod_outer_defs.get(&module_ident.value).unwrap().fhash, + def_fhash, func_def.start, use_name, use_type.clone(), self.ident_type_def_loc(&use_type), + doc_string, ), ); } @@ -1621,18 +1719,22 @@ impl Symbolicator { |use_name, name_start, mod_defs| match mod_defs.structs.get(use_name) { Some(def) => { let ident_type = IdentType::RegularType(use_type.clone()); + let ident_type_def = self.ident_type_def_loc(&ident_type); + let def_fhash = self.mod_outer_defs.get(module_ident).unwrap().fhash; + let doc_string = self.extract_doc_string(&def.name_start, &def_fhash); use_defs.insert( name_start.line, UseDef::new( references, use_pos.file_hash(), name_start, - self.mod_outer_defs.get(module_ident).unwrap().fhash, + def_fhash, def.name_start, use_name, ident_type, ident_type_def, + doc_string, ), ); } @@ -1662,17 +1764,21 @@ impl Symbolicator { if fdef.name == *use_name { let ident_type = IdentType::RegularType(use_type.clone()); let ident_type_def = self.ident_type_def_loc(&ident_type); + + let def_fhash = self.mod_outer_defs.get(module_ident).unwrap().fhash; + let doc_string = self.extract_doc_string(&fdef.start, &def_fhash); use_defs.insert( name_start.line, UseDef::new( references, use_pos.file_hash(), name_start, - self.mod_outer_defs.get(module_ident).unwrap().fhash, + def_fhash, fdef.start, use_name, ident_type, ident_type_def, + doc_string, ), ); } @@ -1700,6 +1806,8 @@ impl Symbolicator { Some(def_loc) => { let ident_type = IdentType::RegularType(id_type.clone()); let ident_type_def = self.ident_type_def_loc(&ident_type); + let doc_string = + self.extract_doc_string(&def_loc.start, &def_loc.fhash); use_defs.insert( name_start.line, UseDef::new( @@ -1711,6 +1819,7 @@ impl Symbolicator { &use_name, ident_type, ident_type_def, + doc_string, ), ); } @@ -1759,6 +1868,8 @@ impl Symbolicator { // in rust) a variable can be re-defined in the same scope replacing the previous // definition + let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); + // enter self-definition for def name let ident_type = IdentType::RegularType(use_type); let ident_type_def = self.ident_type_def_loc(&ident_type); @@ -1773,6 +1884,7 @@ impl Symbolicator { name, ident_type, ident_type_def, + doc_string, ), ); } @@ -1802,6 +1914,7 @@ impl Symbolicator { }; if let Some(def_loc) = scope.get(use_name) { + let doc_string = self.extract_doc_string(&def_loc.start, &def_loc.fhash); let ident_type = IdentType::RegularType(use_type); let ident_type_def = self.ident_type_def_loc(&ident_type); use_defs.insert( @@ -1815,6 +1928,7 @@ impl Symbolicator { use_name, ident_type, ident_type_def, + doc_string, ), ); } else { @@ -2025,7 +2139,11 @@ pub fn on_hover_request(context: &Context, request: &Request, symbols: &Symbols) |u| { let lang_string = LanguageString { language: "".to_string(), - value: format!("{}", u.use_type), + value: if !u.doc_string.is_empty() { + format!("{}\n\n{}", u.use_type, u.doc_string) + } else { + format!("{}", u.use_type) + }, }; let contents = HoverContents::Scalar(MarkedString::LanguageString(lang_string)); let range = None; @@ -2214,7 +2332,7 @@ fn handle_struct_fields(struct_def: StructDef, fields: &mut Vec) } #[cfg(test)] -fn assert_use_def( +fn assert_use_def_with_doc_string( mod_symbols: &UseDefMap, file_name_mapping: &BTreeMap, use_idx: usize, @@ -2225,6 +2343,7 @@ fn assert_use_def( def_file: &str, type_str: &str, type_def: Option<(u32, u32, &str)>, + doc_string: &str, ) { let uses = mod_symbols.get(use_line).unwrap(); let use_def = uses.iter().nth(use_idx).unwrap(); @@ -2237,6 +2356,8 @@ fn assert_use_def( .as_str() .ends_with(def_file)); assert!(type_str == format!("{}", use_def.use_type)); + + assert!(doc_string == use_def.doc_string); match use_def.type_def_loc { Some(type_def_loc) => { let tdef_line = type_def.unwrap().0; @@ -2254,6 +2375,258 @@ fn assert_use_def( } } +#[cfg(test)] +fn assert_use_def( + mod_symbols: &UseDefMap, + file_name_mapping: &BTreeMap, + use_idx: usize, + use_line: u32, + use_col: u32, + def_line: u32, + def_col: u32, + def_file: &str, + type_str: &str, + type_def: Option<(u32, u32, &str)>, +) { + assert_use_def_with_doc_string( + mod_symbols, + file_name_mapping, + use_idx, + use_line, + use_col, + def_line, + def_col, + def_file, + type_str, + type_def, + "", + ) +} + +#[test] +/// Tests if symbolication + doc_string information for documented Move constructs is constructed correctly. +fn docstring_test() { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + path.push("tests/symbols"); + + let (symbols_opt, _) = Symbolicator::get_symbols(path.as_path()).unwrap(); + let symbols = symbols_opt.unwrap(); + + let mut fpath = path.clone(); + fpath.push("sources/M6.move"); + let cpath = dunce::canonicalize(&fpath).unwrap(); + + let mod_symbols = symbols.file_use_defs.get(&cpath).unwrap(); + + // struct def name + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 4, + 11, + 4, + 11, + "M6.move", + "Symbols::M6::DocumentedStruct", + Some((4, 11, "M6.move")), + "This is a documented struct\nWith a multi-line docstring\n", + ); + + // const def name + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 10, + 10, + 10, + 10, + "M6.move", + "u64", + None, + "Constant containing the answer to the universe\n", + ); + + // function def name + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 14, + 8, + 14, + 8, + "M6.move", + "fun Symbols::M6::unpack(Symbols::M6::DocumentedStruct): u64", + None, + "A documented function that unpacks a DocumentedStruct\n", + ); + // param var (unpack function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 1, + 14, + 15, + 14, + 15, + "M6.move", + "Symbols::M6::DocumentedStruct", + Some((4, 11, "M6.move")), + "A documented function that unpacks a DocumentedStruct\n", + ); + // struct name in param type (unpack function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 2, + 14, + 18, + 4, + 11, + "M6.move", + "Symbols::M6::DocumentedStruct", + Some((4, 11, "M6.move")), + "This is a documented struct\nWith a multi-line docstring\n", + ); + // struct name in unpack (unpack function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 15, + 12, + 4, + 11, + "M6.move", + "Symbols::M6::DocumentedStruct", + Some((4, 11, "M6.move")), + "This is a documented struct\nWith a multi-line docstring\n", + ); + // field name in unpack (unpack function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 1, + 15, + 31, + 6, + 8, + "M6.move", + "u64", + None, + "A documented field\n", + ); + // moved var in unpack assignment (unpack function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 3, + 15, + 59, + 14, + 15, + "M6.move", + "Symbols::M6::DocumentedStruct", + Some((4, 11, "M6.move")), + "A documented function that unpacks a DocumentedStruct\n", + ); + + // docstring construction for multi-line /** .. */ based strings + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 26, + 8, + 26, + 8, + "M6.move", + "fun Symbols::M6::other_doc_struct(): Symbols::M7::OtherDocStruct", + Some((3, 11, "M7.move")), + "\nThis is a multiline docstring\n\nThis docstring has empty lines.\n\nIt uses the ** format instead of ///\n\n", + ); + + // docstring construction for single-line /** .. */ based strings + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 31, + 8, + 31, + 8, + "M6.move", + "fun Symbols::M6::acq(address): u64 acquires Symbols::M6::DocumentedStruct", + None, + "Asterix based single-line docstring\n", + ); + + /* Test doc_string construction for struct/function imported from another module */ + + // other module struct name (other_doc_struct function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 1, + 26, + 41, + 3, + 11, + "M7.move", + "Symbols::M7::OtherDocStruct", + Some((3, 11, "M7.move")), + "Documented struct in another module\n", + ); + + // function name in a call (other_doc_struct function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 0, + 27, + 21, + 9, + 15, + "M7.move", + "fun Symbols::M7::create_other_struct(u64): Symbols::M7::OtherDocStruct", + Some((3, 11, "M7.move")), + "Documented initializer in another module\n", + ); + + // const in param (other_doc_struct function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 1, + 27, + 41, + 10, + 10, + "M6.move", + "u64", + None, + "Constant containing the answer to the universe\n", + ); + + // // other documented struct name imported (other_doc_struct_import function) + assert_use_def_with_doc_string( + mod_symbols, + &symbols.file_name_mapping, + 1, + 38, + 35, + 3, + 11, + "M7.move", + "Symbols::M7::OtherDocStruct", + Some((3, 11, "M7.move")), + "Documented struct in another module\n", + ); +} + #[test] /// Tests if symbolication information for specific Move constructs has been constructed correctly. fn symbols_test() { diff --git a/language/move-analyzer/tests/symbols/sources/M6.move b/language/move-analyzer/tests/symbols/sources/M6.move new file mode 100644 index 0000000000..aa3427fa8c --- /dev/null +++ b/language/move-analyzer/tests/symbols/sources/M6.move @@ -0,0 +1,42 @@ +module Symbols::M6 { + + /// This is a documented struct + /// With a multi-line docstring + struct DocumentedStruct has key, drop, store { + /// A documented field + documented_field: u64, + } + + /// Constant containing the answer to the universe + const DOCUMENTED_CONSTANT: u64 = 42; + + + /// A documented function that unpacks a DocumentedStruct + fun unpack(s: DocumentedStruct): u64 { + let DocumentedStruct { documented_field: value } = s; + value + } + + /** + This is a multiline docstring + + This docstring has empty lines. + + It uses the ** format instead of /// + */ + fun other_doc_struct(): Symbols::M7::OtherDocStruct { + Symbols::M7::create_other_struct(DOCUMENTED_CONSTANT) + } + + /** Asterix based single-line docstring */ + fun acq(addr: address): u64 acquires DocumentedStruct { + let val = borrow_global(addr); + val.documented_field + } + + use Symbols::M7::{Self, OtherDocStruct}; + + fun other_doc_struct_import(): OtherDocStruct { + M7::create_other_struct(7) + } +} diff --git a/language/move-analyzer/tests/symbols/sources/M7.move b/language/move-analyzer/tests/symbols/sources/M7.move new file mode 100644 index 0000000000..b4165da101 --- /dev/null +++ b/language/move-analyzer/tests/symbols/sources/M7.move @@ -0,0 +1,13 @@ +module Symbols::M7 { + + /// Documented struct in another module + struct OtherDocStruct has drop { + /// Documented field in another module + some_field: u64, + } + + /// Documented initializer in another module + public fun create_other_struct(v: u64): OtherDocStruct { + OtherDocStruct { some_field: v } + } +} From 382264e01cf6e659a9f20d6e40e1f45b689d63c0 Mon Sep 17 00:00:00 2001 From: Zou Guangxian Date: Mon, 8 Aug 2022 05:11:11 +0800 Subject: [PATCH 040/169] display bitwise or operation incorrectly. (#351) --- language/documentation/book/src/integers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/book/src/integers.md b/language/documentation/book/src/integers.md index a78f1a8668..00f1347082 100644 --- a/language/documentation/book/src/integers.md +++ b/language/documentation/book/src/integers.md @@ -73,7 +73,7 @@ Bitwise operations do not abort. | Syntax | Operation | Description |--------|------------|------------ | `&` | bitwise and| Performs a boolean and for each bit pairwise -| `|` | bitwise or | Performs a boolean or for each bit pairwise +| `\|` | bitwise or | Performs a boolean or for each bit pairwise | `^` | bitwise xor| Performs a boolean exclusive or for each bit pairwise ### Bit Shifts From 13a7e43e724d5187e88211761f8ebbf43d79bf2a Mon Sep 17 00:00:00 2001 From: 0xbe1 <101405096+0xbe1@users.noreply.github.com> Date: Mon, 8 Aug 2022 05:11:37 +0800 Subject: [PATCH 041/169] fix broken link (#348) --- language/documentation/book/src/structs-and-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/book/src/structs-and-resources.md b/language/documentation/book/src/structs-and-resources.md index ba73d2f1d6..ed778f0f31 100644 --- a/language/documentation/book/src/structs-and-resources.md +++ b/language/documentation/book/src/structs-and-resources.md @@ -394,7 +394,7 @@ module m { Only structs with the `key` ability can be saved directly in [persistent global storage](./global-storage-operators.md). All values stored within those `key` -structs must have the `store` abilities. See the [ability](./abilities] and +structs must have the `store` abilities. See the [ability](./abilities.md) and [global storage](./global-storage-operators.md) chapters for more detail. ## Examples From 6f36a9733a741afbb1d56249e7e1f50a8c5093d9 Mon Sep 17 00:00:00 2001 From: jiangying Date: Mon, 8 Aug 2022 05:12:40 +0800 Subject: [PATCH 042/169] [doc] update vector.md vector::index_of (#342) * [doc] update vector.md vector::index_of * update --- language/documentation/book/src/unit-testing.md | 2 +- language/documentation/book/src/vector.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/language/documentation/book/src/unit-testing.md b/language/documentation/book/src/unit-testing.md index 868e3b3c40..f81cc4d488 100644 --- a/language/documentation/book/src/unit-testing.md +++ b/language/documentation/book/src/unit-testing.md @@ -276,7 +276,7 @@ module 0x1::my_module { } ``` -we would get get the following output when running the tests: +we would get the following output when running the tests: ``` $ move test -g diff --git a/language/documentation/book/src/vector.md b/language/documentation/book/src/vector.md index 2bbce46788..a267222f75 100644 --- a/language/documentation/book/src/vector.md +++ b/language/documentation/book/src/vector.md @@ -104,7 +104,7 @@ library: | `vector::contains(v: &vector, e: &T): bool` | Return true if `e` is in the vector `v` | Never | | `vector::swap(v: &mut vector, i: u64, j: u64)` | Swaps the elements at the `i`th and `j`th indices in the vector `v`.| If `i` or `j` is out of bounds | | `vector::reverse(v: &mut vector)` | Reverses the order of the elements in the vector `v` in place | Never | -| `vector::index_of(v: &vector, e: &T): bool` | Return `(true, i)` if `e` is in the vector `v` at index `i`. Otherwise, returns `(false, 0)`.| Never | +| `vector::index_of(v: &vector, e: &T): (bool, u64)` | Return `(true, i)` if `e` is in the vector `v` at index `i`. Otherwise, returns `(false, 0)`.| Never | | `vector::remove(v: &mut vector, i: u64): T` | Remove the `i`th element of the vector `v`, shifting all subsequent elements. This is O(n) and preserves ordering of elements in the vector. | If `i` is out of bounds. | | `vector::swap_remove(v: &mut vector, i: u64): T` | Swap the `i`th element of the vector `v` with the last element and then pop the vector, This is O(1), but does not preserve ordering of elements in the vector. | If `i` is out of bounds. | From 5abe4321c26eea04263a4ae3aaf37088c2c856a3 Mon Sep 17 00:00:00 2001 From: Bo Wu Date: Sun, 7 Aug 2022 17:33:51 -0700 Subject: [PATCH 043/169] Make abi generation work copyable struct txn arg (#356) --- Cargo.lock | 1 + language/move-prover/move-abigen/Cargo.toml | 1 + .../move-prover/move-abigen/src/abigen.rs | 49 +++++++++++++++--- language/move-prover/move-abigen/src/lib.rs | 2 + .../tests/sources/script_fun_in_module.move | 4 ++ .../this_is_script_fun_with_string_args.abi | Bin 0 -> 164 bytes .../move-abigen/tests/testsuite.rs | 4 ++ 7 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 language/move-prover/move-abigen/tests/sources/script_fun_in_module/this_is_script_fun_with_string_args.abi diff --git a/Cargo.lock b/Cargo.lock index 4820df75ca..6e79b3a616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2274,6 +2274,7 @@ dependencies = [ "datatest-stable", "heck 0.3.2", "log", + "move-binary-format", "move-bytecode-verifier", "move-command-line-common", "move-core-types", diff --git a/language/move-prover/move-abigen/Cargo.toml b/language/move-prover/move-abigen/Cargo.toml index 7d4f5c68b0..c02c5569a9 100644 --- a/language/move-prover/move-abigen/Cargo.toml +++ b/language/move-prover/move-abigen/Cargo.toml @@ -10,6 +10,7 @@ license = "Apache-2.0" # diem dependencies move-model = { path = "../../move-model" } move-core-types = { path = "../../move-core/types" } +move-binary-format = { path = "../../move-binary-format" } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-command-line-common = { path = "../../move-command-line-common" } bcs = "0.1.2" diff --git a/language/move-prover/move-abigen/src/abigen.rs b/language/move-prover/move-abigen/src/abigen.rs index bdff55dc74..8a5a34288e 100644 --- a/language/move-prover/move-abigen/src/abigen.rs +++ b/language/move-prover/move-abigen/src/abigen.rs @@ -7,12 +7,13 @@ use log::{debug, info, warn}; use anyhow::bail; use heck::SnakeCase; +use move_binary_format::file_format::Ability; use move_bytecode_verifier::script_signature; use move_command_line_common::files::MOVE_COMPILED_EXTENSION; use move_core_types::{ abi::{ArgumentABI, ScriptABI, ScriptFunctionABI, TransactionScriptABI, TypeArgumentABI}, identifier::IdentStr, - language_storage::TypeTag, + language_storage::{StructTag, TypeTag}, }; use move_model::{ model::{FunctionEnv, GlobalEnv, ModuleEnv}, @@ -150,7 +151,10 @@ impl<'env> Abigen<'env> { _ => false, }) .all(|param| { - matches!(self.get_type_tag(¶m.1), Err(_) | Ok(Some(_))) + matches!( + self.get_type_tag(¶m.1, module_env), + Err(_) | Ok(Some(_)) + ) }) && func.get_return_count() == 0 }) @@ -188,10 +192,15 @@ impl<'env> Abigen<'env> { ty::Type::Reference(false, inner) => { !matches!(&**inner, ty::Type::Primitive(ty::PrimitiveType::Signer)) } + ty::Type::Struct(module_id, struct_id, _) => { + let struct_module_env = module_env.env.get_module(*module_id); + let abilities = struct_module_env.get_struct(*struct_id).get_abilities(); + abilities.has_ability(Ability::Copy) && !abilities.has_ability(Ability::Key) + } _ => true, }) .map(|param| { - let tag = self.get_type_tag(¶m.1)?.unwrap(); + let tag = self.get_type_tag(¶m.1, module_env)?.unwrap(); Ok(ArgumentABI::new( symbol_pool.string(param.0).to_string(), tag, @@ -247,7 +256,11 @@ impl<'env> Abigen<'env> { } } - fn get_type_tag(&self, ty0: &ty::Type) -> anyhow::Result> { + fn get_type_tag( + &self, + ty0: &ty::Type, + module_env: &ModuleEnv<'env>, + ) -> anyhow::Result> { use ty::Type::*; let tag = match ty0 { Primitive(prim) => { @@ -265,14 +278,38 @@ impl<'env> Abigen<'env> { } } Vector(ty) => { - let tag = match self.get_type_tag(ty)? { + let tag = match self.get_type_tag(ty, module_env)? { Some(tag) => tag, None => return Ok(None), }; TypeTag::Vector(Box::new(tag)) } + Struct(module_id, struct_id, vec_type) => { + let expect_msg = format!("type {:?} is not allowed in scription function", ty0); + let struct_module_env = module_env.env.get_module(*module_id); + let abilities = struct_module_env.get_struct(*struct_id).get_abilities(); + if abilities.has_ability(Ability::Copy) && !abilities.has_ability(Ability::Key) { + TypeTag::Struct(StructTag { + address: *struct_module_env.self_address(), + module: struct_module_env.get_identifier(), + name: struct_module_env + .get_struct(*struct_id) + .get_identifier() + .unwrap_or_else(|| panic!("{}", expect_msg)), + type_params: vec_type + .iter() + .map(|e| { + self.get_type_tag(e, module_env) + .unwrap_or_else(|_| panic!("{}", expect_msg)) + }) + .map(|e| e.unwrap_or_else(|| panic!("{}", expect_msg))) + .collect(), + }) + } else { + return Ok(None); + } + } Tuple(_) - | Struct(_, _, _) | TypeParameter(_) | Fun(_, _) | TypeDomain(_) diff --git a/language/move-prover/move-abigen/src/lib.rs b/language/move-prover/move-abigen/src/lib.rs index 758d2500fa..5abe5ae7d2 100644 --- a/language/move-prover/move-abigen/src/lib.rs +++ b/language/move-prover/move-abigen/src/lib.rs @@ -4,6 +4,8 @@ #![forbid(unsafe_code)] +extern crate core; + mod abigen; pub use crate::abigen::*; diff --git a/language/move-prover/move-abigen/tests/sources/script_fun_in_module.move b/language/move-prover/move-abigen/tests/sources/script_fun_in_module.move index 27e6f34995..1d4548fbd9 100644 --- a/language/move-prover/move-abigen/tests/sources/script_fun_in_module.move +++ b/language/move-prover/move-abigen/tests/sources/script_fun_in_module.move @@ -1,5 +1,7 @@ address 0x1 { module ScriptFunInModule { + use std::string::String; + struct NoCall has drop {} /// This is a doc comment on this script fun @@ -26,6 +28,8 @@ module ScriptFunInModule { /// This is a comment on a non-callable script function public entry fun this_is_script_fun_with_signer(account: signer, _another_arg: u64) { } + /// This is a comment on a non-callable script function + public entry fun this_is_script_fun_with_string_args(account: &signer, _val: String) { } public fun foo() { } fun bar() { } diff --git a/language/move-prover/move-abigen/tests/sources/script_fun_in_module/this_is_script_fun_with_string_args.abi b/language/move-prover/move-abigen/tests/sources/script_fun_in_module/this_is_script_fun_with_string_args.abi new file mode 100644 index 0000000000000000000000000000000000000000..43d35aca5e8f1ca180f7864c5c490368aa08ca24 GIT binary patch literal 164 zcmZQnF3HF&jt8RR!|q*ilVqU}S?>%@z!H0RtBRW&1B~ literal 0 HcmV?d00001 diff --git a/language/move-prover/move-abigen/tests/testsuite.rs b/language/move-prover/move-abigen/tests/testsuite.rs index a795bf5747..2d7b5f0373 100644 --- a/language/move-prover/move-abigen/tests/testsuite.rs +++ b/language/move-prover/move-abigen/tests/testsuite.rs @@ -27,6 +27,10 @@ fn test_runner(path: &Path) -> datatest_stable::Result<()> { let mut options = Options::create_from_args(&args)?; options.setup_logging_for_test(); options.abigen.compiled_script_directory = "tests/sources".to_string(); + options.move_deps.push("../../move-stdlib".to_string()); + options + .move_named_address_values + .push("std=0x1".to_string()); test_abigen(path, options, "abi")?; From cd6f5967af7417d71cd4057388f47ace19ed2915 Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Tue, 9 Aug 2022 01:31:12 +0800 Subject: [PATCH 044/169] fix some typos in the book (#352) * fix some typos in the book * Update language/documentation/book/src/structs-and-resources.md Co-authored-by: Sam Blackshear --- language/documentation/book/src/abort-and-assert.md | 1 - language/documentation/book/src/address.md | 2 +- language/documentation/book/src/packages.md | 1 + language/documentation/book/src/standard-library.md | 2 -- language/documentation/book/src/structs-and-resources.md | 2 +- language/documentation/book/src/unit-testing.md | 1 + 6 files changed, 4 insertions(+), 5 deletions(-) diff --git a/language/documentation/book/src/abort-and-assert.md b/language/documentation/book/src/abort-and-assert.md index 87ed86bafb..ce3e87478e 100644 --- a/language/documentation/book/src/abort-and-assert.md +++ b/language/documentation/book/src/abort-and-assert.md @@ -205,4 +205,3 @@ let b = else abort 42; // ^^^^^^^^ `abort 42` has type `bool` ``` -```` diff --git a/language/documentation/book/src/address.md b/language/documentation/book/src/address.md index 73753bcd1a..eb175caad6 100644 --- a/language/documentation/book/src/address.md +++ b/language/documentation/book/src/address.md @@ -16,7 +16,7 @@ literals. To distinguish when an address is being used in an expression context or not, the syntax when using an address differs depending on the context where it's used: -* When an address is used as an expression the address must be prefixed by the `@` character, i.e., `@`[``](./integers.md)` or `@`. +* When an address is used as an expression the address must be prefixed by the `@` character, i.e., `@`[``](./integers.md) or `@`. * Outside of expression contexts, the address may be written without the leading `@` character, i.e., [``](./integers.md) or ``. In general, you can think of `@` as an operator that takes an address from being a namespace item to being an expression item. diff --git a/language/documentation/book/src/packages.md b/language/documentation/book/src/packages.md index 37947cc59d..c4abace5ca 100644 --- a/language/documentation/book/src/packages.md +++ b/language/documentation/book/src/packages.md @@ -122,6 +122,7 @@ individually: ### Declaration Let's say we have a Move module in `example_pkg/sources/A.move` as follows: + ```move module named_addr::A { public fun x(): address { @named_addr } diff --git a/language/documentation/book/src/standard-library.md b/language/documentation/book/src/standard-library.md index 8f17814977..7dcd8f2251 100644 --- a/language/documentation/book/src/standard-library.md +++ b/language/documentation/book/src/standard-library.md @@ -486,12 +486,10 @@ Used for extension points, should be not used under most circumstances. Construc ## fixed_point32 - The `fixed_point32` module defines a fixed-point numeric type with 32 integer bits and 32 fractional bits. Internally, this is represented as a `u64` integer wrapped in a struct to make a unique `fixed_point32` type. Since the numeric representation is a binary one, some decimal values may not be exactly representable, but it provides more than 9 decimal digits of precision both before and after the decimal point (18 digits total). For comparison, double precision floating-point has less than 16 decimal digits of precision, so you should be careful about using floating-point to convert these values to decimal. ### Types - Represents a fixed-point numeric number with 32 fractional bits. ```move diff --git a/language/documentation/book/src/structs-and-resources.md b/language/documentation/book/src/structs-and-resources.md index ed778f0f31..8b1e226478 100644 --- a/language/documentation/book/src/structs-and-resources.md +++ b/language/documentation/book/src/structs-and-resources.md @@ -394,7 +394,7 @@ module m { Only structs with the `key` ability can be saved directly in [persistent global storage](./global-storage-operators.md). All values stored within those `key` -structs must have the `store` abilities. See the [ability](./abilities.md) and +structs must have the `store` ability. See the [ability](./abilities) and [global storage](./global-storage-operators.md) chapters for more detail. ## Examples diff --git a/language/documentation/book/src/unit-testing.md b/language/documentation/book/src/unit-testing.md index f81cc4d488..77daecd2af 100644 --- a/language/documentation/book/src/unit-testing.md +++ b/language/documentation/book/src/unit-testing.md @@ -113,6 +113,7 @@ $ move -h A simple module using some of the unit testing features is shown in the following example: First create an empty package and change directory into it: + ``` $ move new TestExample; cd TestExample ``` From de012441fa6057e49d9b6082cde6f233e5597688 Mon Sep 17 00:00:00 2001 From: East Agile Date: Tue, 9 Aug 2022 05:16:40 +0700 Subject: [PATCH 045/169] [Movey] Add command to save Movey API Token (#226) * Add subcommand login, read token from user # Conflicts: # Cargo.lock # language/tools/move-cli/Cargo.toml * Store token to file, add unit tests # Conflicts: # Cargo.lock * Refactor test code * Refactor test code to run in parallel, add license header * Refactor tests to run in current dir * Refactor to be specific to Movey * Refactor movey-login logic, refactor movey tests * Add OS conditional compilation when create movey credential file, more precise error when read movey credential --- Cargo.lock | 25 ++ language/move-command-line-common/Cargo.toml | 2 + language/move-command-line-common/src/env.rs | 14 ++ language/move-command-line-common/src/lib.rs | 1 + .../src/movey_constants.rs | 7 + language/tools/move-cli/Cargo.toml | 2 + language/tools/move-cli/src/base/mod.rs | 1 + .../tools/move-cli/src/base/movey_login.rs | 238 ++++++++++++++++++ language/tools/move-cli/src/lib.rs | 5 +- language/tools/move-cli/tests/cli_tests.rs | 124 ++++++++- .../src/source_package/manifest_parser.rs | 11 +- 11 files changed, 418 insertions(+), 12 deletions(-) create mode 100644 language/move-command-line-common/src/movey_constants.rs create mode 100644 language/tools/move-cli/src/base/movey_login.rs diff --git a/Cargo.lock b/Cargo.lock index 6e79b3a616..acb9c62c98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -634,6 +634,16 @@ dependencies = [ "itertools 0.10.1", ] +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "config" version = "0.11.0" @@ -2444,6 +2454,7 @@ dependencies = [ "serde 1.0.130", "serde_yaml", "tempfile", + "toml_edit", "walkdir", ] @@ -2453,9 +2464,11 @@ version = "0.1.0" dependencies = [ "anyhow", "difference", + "dirs-next", "hex", "move-core-types", "num-bigint 0.4.0", + "once_cell", "serde 1.0.130", "sha2", "walkdir", @@ -5172,6 +5185,18 @@ dependencies = [ "serde 1.0.130", ] +[[package]] +name = "toml_edit" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5376256e44f2443f8896ac012507c19a012df0fe8758b55246ae51a2279db51f" +dependencies = [ + "combine", + "indexmap", + "itertools 0.10.1", + "serde 1.0.130", +] + [[package]] name = "tracing" version = "0.1.26" diff --git a/language/move-command-line-common/Cargo.toml b/language/move-command-line-common/Cargo.toml index 361d3431c2..3804ad44ce 100644 --- a/language/move-command-line-common/Cargo.toml +++ b/language/move-command-line-common/Cargo.toml @@ -12,10 +12,12 @@ edition = "2021" [dependencies] anyhow = "1.0.52" difference = "2.0.0" +dirs-next = "2.0.0" walkdir = "2.3.1" sha2 = "0.9.3" hex = "0.4.3" num-bigint = "0.4.0" +once_cell = "1.7.2" serde = { version = "1.0.124", features = ["derive"] } move-core-types = { path = "../move-core/types" } diff --git a/language/move-command-line-common/src/env.rs b/language/move-command-line-common/src/env.rs index 888a01cca3..ac247159c8 100644 --- a/language/move-command-line-common/src/env.rs +++ b/language/move-command-line-common/src/env.rs @@ -2,6 +2,8 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use once_cell::sync::Lazy; + /// An environment variable which can be set to cause the move compiler to generate /// file formats at a given version. Only version v5 and greater are supported. const BYTECODE_VERSION_ENV_VAR: &str = "MOVE_BYTECODE_VERSION"; @@ -22,3 +24,15 @@ pub fn read_bool_env_var(v: &str) -> bool { let val = read_env_var(v).to_lowercase(); val.parse::() == Ok(true) || val.parse::() == Ok(1) } + +pub static MOVE_HOME: Lazy = Lazy::new(|| { + std::env::var("MOVE_HOME").unwrap_or_else(|_| { + format!( + "{}/.move", + dirs_next::home_dir() + .expect("user's home directory not found") + .to_str() + .unwrap() + ) + }) +}); diff --git a/language/move-command-line-common/src/lib.rs b/language/move-command-line-common/src/lib.rs index 5bb4087c9a..201829bad2 100644 --- a/language/move-command-line-common/src/lib.rs +++ b/language/move-command-line-common/src/lib.rs @@ -8,6 +8,7 @@ pub mod address; pub mod character_sets; pub mod env; pub mod files; +pub mod movey_constants; pub mod parser; pub mod testing; pub mod types; diff --git a/language/move-command-line-common/src/movey_constants.rs b/language/move-command-line-common/src/movey_constants.rs new file mode 100644 index 0000000000..4567bdbf4d --- /dev/null +++ b/language/move-command-line-common/src/movey_constants.rs @@ -0,0 +1,7 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(debug_assertions)] +pub const MOVEY_URL: &str = "https://movey-app-staging.herokuapp.com"; +#[cfg(not(debug_assertions))] +pub const MOVEY_URL: &str = "https://www.movey.net"; diff --git a/language/tools/move-cli/Cargo.toml b/language/tools/move-cli/Cargo.toml index efaca163b1..e060a4133e 100644 --- a/language/tools/move-cli/Cargo.toml +++ b/language/tools/move-cli/Cargo.toml @@ -21,6 +21,8 @@ tempfile = "3.2.0" walkdir = "2.3.1" codespan-reporting = "0.11.1" itertools = "0.10.0" +toml_edit = { version = "0.14.3", features = ["easy"] } + bcs = "0.1.2" move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-disassembler = { path = "../move-disassembler" } diff --git a/language/tools/move-cli/src/base/mod.rs b/language/tools/move-cli/src/base/mod.rs index 0633fcc2dd..03b0d566c3 100644 --- a/language/tools/move-cli/src/base/mod.rs +++ b/language/tools/move-cli/src/base/mod.rs @@ -7,6 +7,7 @@ pub mod disassemble; pub mod docgen; pub mod errmap; pub mod info; +pub mod movey_login; pub mod new; pub mod prove; pub mod test; diff --git a/language/tools/move-cli/src/base/movey_login.rs b/language/tools/move-cli/src/base/movey_login.rs new file mode 100644 index 0000000000..214f5ae9c6 --- /dev/null +++ b/language/tools/move-cli/src/base/movey_login.rs @@ -0,0 +1,238 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::{bail, Result}; +use clap::Parser; +use move_command_line_common::{env::MOVE_HOME, movey_constants::MOVEY_URL}; +use std::{fs, fs::File, io, path::PathBuf}; +use toml_edit::easy::{map::Map, Value}; + +pub const MOVEY_CREDENTIAL_PATH: &str = "/movey_credential.toml"; + +#[derive(Parser)] +#[clap(name = "movey-login")] +pub struct MoveyLogin; + +impl MoveyLogin { + pub fn execute(self) -> Result<()> { + println!( + "Please paste the API Token found on {}/settings/tokens below", + MOVEY_URL + ); + let mut line = String::new(); + loop { + match io::stdin().read_line(&mut line) { + Ok(_) => { + line = line.trim().to_string(); + if !line.is_empty() { + break; + } + println!("Invalid API Token. Try again!"); + } + Err(err) => { + bail!("Error reading file: {}", err); + } + } + } + Self::save_credential(line, MOVE_HOME.clone())?; + println!("Token for Movey saved."); + Ok(()) + } + + pub fn save_credential(token: String, move_home: String) -> Result<()> { + fs::create_dir_all(&move_home)?; + let credential_path = move_home + MOVEY_CREDENTIAL_PATH; + let credential_file = PathBuf::from(&credential_path); + if !credential_file.exists() { + create_credential_file(&credential_path)?; + } + + let old_contents: String; + match fs::read_to_string(&credential_path) { + Ok(contents) => { + old_contents = contents; + } + Err(error) => bail!("Error reading input: {}", error), + } + let mut toml: Value = old_contents.parse().map_err(|e| { + anyhow::Error::from(e).context(format!( + "could not parse input at {} as TOML", + &credential_path + )) + })?; + + // only update token key, keep the rest of the file intact + if let Some(registry) = toml.as_table_mut().unwrap().get_mut("registry") { + if let Some(toml_token) = registry.as_table_mut().unwrap().get_mut("token") { + *toml_token = Value::String(token); + } else { + registry + .as_table_mut() + .unwrap() + .insert(String::from("token"), Value::String(token)); + } + } else { + let mut value = Map::new(); + value.insert(String::from("token"), Value::String(token)); + toml.as_table_mut() + .unwrap() + .insert(String::from("registry"), Value::Table(value)); + } + + let new_contents = toml.to_string(); + fs::write(credential_file, new_contents).expect("Unable to write file"); + Ok(()) + } +} + +#[cfg(unix)] +fn create_credential_file(credential_path: &str) -> Result<()> { + use std::os::unix::fs::PermissionsExt; + let credential_file = File::create(&credential_path)?; + + let mut perms = credential_file.metadata()?.permissions(); + perms.set_mode(0o600); + credential_file.set_permissions(perms)?; + Ok(()) +} + +#[cfg(windows)] +#[allow(unused)] +fn create_credential_file(credential_path: &str) -> Result<()> { + let windows_path = credential_path.replace("/", "\\"); + File::create(&windows_path)?; + Ok(()) +} + +#[cfg(not(any(unix, windows)))] +#[allow(unused)] +fn create_credential_file(credential_path: &str) -> Result<()> { + bail!("OS not supported") +} + +#[cfg(test)] +mod tests { + use super::*; + use std::env; + + fn setup_move_home(test_path: &str) -> (String, String) { + let cwd = env::current_dir().unwrap(); + let mut move_home: String = String::from(cwd.to_string_lossy()); + if !test_path.is_empty() { + move_home.push_str(&test_path); + } else { + move_home.push_str("/test"); + } + let credential_path = move_home.clone() + MOVEY_CREDENTIAL_PATH; + (move_home, credential_path) + } + + fn clean_up(move_home: &str) { + let _ = fs::remove_dir_all(move_home); + } + + #[test] + fn save_credential_works_if_no_credential_file_exists() { + let (move_home, credential_path) = + setup_move_home("/save_credential_works_if_no_credential_file_exists"); + let _ = fs::remove_dir_all(&move_home); + MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + + clean_up(&move_home); + } + + #[test] + fn save_credential_works_if_empty_credential_file_exists() { + let (move_home, credential_path) = + setup_move_home("/save_credential_works_if_empty_credential_file_exists"); + + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + assert!(toml.as_table_mut().unwrap().get_mut("registry").is_none()); + + MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + + clean_up(&move_home); + } + + #[test] + fn save_credential_works_if_token_field_exists() { + let (move_home, credential_path) = + setup_move_home("/save_credential_works_if_token_field_exists"); + + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); + + let old_content = + String::from("[registry]\ntoken = \"old_test_token\"\nversion = \"0.0.0\"\n"); + fs::write(&credential_path, old_content).expect("Unable to write file"); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("old_test_token")); + assert!(!token.to_string().contains("new_world")); + + MoveyLogin::save_credential(String::from("new_world"), move_home.clone()).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("new_world")); + assert!(!token.to_string().contains("old_test_token")); + let version = registry.as_table_mut().unwrap().get_mut("version").unwrap(); + assert!(version.to_string().contains("0.0.0")); + + clean_up(&move_home); + } + + #[test] + fn save_credential_works_if_empty_token_field_exists() { + let (move_home, credential_path) = + setup_move_home("/save_credential_works_if_empty_token_field_exists"); + + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); + + let old_content = String::from("[registry]\ntoken = \"\"\nversion = \"0.0.0\"\n"); + fs::write(&credential_path, old_content).expect("Unable to write file"); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(!token.to_string().contains("test_token")); + + MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + let version = registry.as_table_mut().unwrap().get_mut("version").unwrap(); + assert!(version.to_string().contains("0.0.0")); + + clean_up(&move_home); + } +} diff --git a/language/tools/move-cli/src/lib.rs b/language/tools/move-cli/src/lib.rs index e3206a904c..f7cef69805 100644 --- a/language/tools/move-cli/src/lib.rs +++ b/language/tools/move-cli/src/lib.rs @@ -4,7 +4,7 @@ use base::{ build::Build, coverage::Coverage, disassemble::Disassemble, docgen::Docgen, errmap::Errmap, - info::Info, new::New, prove::Prove, test::Test, + info::Info, movey_login::MoveyLogin, new::New, prove::Prove, test::Test, }; use move_package::BuildConfig; @@ -91,6 +91,8 @@ pub enum Command { #[clap(subcommand)] cmd: experimental::cli::ExperimentalCommand, }, + #[clap(name = "movey-login")] + MoveyLogin(MoveyLogin), } pub fn run_cli( @@ -121,6 +123,7 @@ pub fn run_cli( &storage_dir, ), Command::Experimental { storage_dir, cmd } => cmd.handle_command(&move_args, &storage_dir), + Command::MoveyLogin(c) => c.execute(), } } diff --git a/language/tools/move-cli/tests/cli_tests.rs b/language/tools/move-cli/tests/cli_tests.rs index b77954862b..f0c6d060c2 100644 --- a/language/tools/move-cli/tests/cli_tests.rs +++ b/language/tools/move-cli/tests/cli_tests.rs @@ -2,9 +2,16 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use move_cli::sandbox::commands::test; +use move_cli::{base::movey_login::MOVEY_CREDENTIAL_PATH, sandbox::commands::test}; +use move_command_line_common::movey_constants::MOVEY_URL; +#[cfg(unix)] +use std::fs::File; +use std::{env, fs, io::Write}; -use std::path::PathBuf; +#[cfg(unix)] +use std::os::unix::fs::PermissionsExt; +use std::{path::PathBuf, process::Stdio}; +use toml_edit::easy::Value; pub const CLI_METATEST_PATH: [&str; 3] = ["tests", "metatests", "args.txt"]; @@ -53,3 +60,116 @@ fn cross_process_locking_git_deps() { .expect("Package2 failed"); handle.join().unwrap(); } + +#[test] +fn save_credential_works() { + let cli_exe = env!("CARGO_BIN_EXE_move"); + let (move_home, credential_path) = setup_move_home("/save_credential_works"); + assert!(fs::read_to_string(&credential_path).is_err()); + + match std::process::Command::new(cli_exe) + .env("MOVE_HOME", &move_home) + .current_dir(".") + .args(["movey-login"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + { + Ok(child) => { + let token = "test_token"; + child + .stdin + .as_ref() + .unwrap() + .write_all(token.as_bytes()) + .unwrap(); + match child.wait_with_output() { + Ok(output) => { + assert!(String::from_utf8_lossy(&output.stdout).contains(&format!( + "Please paste the API Token found on {}/settings/tokens below", + MOVEY_URL + ))); + Ok(()) + } + Err(error) => Err(error), + } + } + Err(error) => Err(error), + } + .unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + + clean_up(&move_home) +} + +#[cfg(unix)] +#[test] +fn save_credential_fails_if_undeletable_credential_file_exists() { + let cli_exe = env!("CARGO_BIN_EXE_move"); + let (move_home, credential_path) = + setup_move_home("/save_credential_fails_if_undeletable_credential_file_exists"); + let file = File::create(&credential_path).unwrap(); + let mut perms = file.metadata().unwrap().permissions(); + perms.set_mode(0o000); + file.set_permissions(perms).unwrap(); + + match std::process::Command::new(cli_exe) + .env("MOVE_HOME", &move_home) + .current_dir(".") + .args(["movey-login"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + { + Ok(child) => { + let token = "test_token"; + child + .stdin + .as_ref() + .unwrap() + .write_all(token.as_bytes()) + .unwrap(); + match child.wait_with_output() { + Ok(output) => { + assert!(String::from_utf8_lossy(&output.stdout).contains(&format!( + "Please paste the API Token found on {}/settings/tokens below", + MOVEY_URL + ))); + assert!(String::from_utf8_lossy(&output.stderr) + .contains("Error: Error reading input: Permission denied (os error 13)")); + Ok(()) + } + Err(error) => Err(error), + } + } + Err(error) => Err(error), + } + .unwrap(); + + let mut perms = file.metadata().unwrap().permissions(); + perms.set_mode(0o600); + file.set_permissions(perms).unwrap(); + let _ = fs::remove_file(&credential_path); + + clean_up(&move_home) +} + +fn setup_move_home(test_path: &str) -> (String, String) { + let cwd = env::current_dir().unwrap(); + let mut move_home: String = String::from(cwd.to_string_lossy()); + move_home.push_str(&test_path); + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + let credential_path = move_home.clone() + MOVEY_CREDENTIAL_PATH; + (move_home, credential_path) +} + +fn clean_up(move_home: &str) { + let _ = fs::remove_dir_all(move_home); +} diff --git a/language/tools/move-package/src/source_package/manifest_parser.rs b/language/tools/move-package/src/source_package/manifest_parser.rs index 69f17cce68..e6139c1d67 100644 --- a/language/tools/move-package/src/source_package/manifest_parser.rs +++ b/language/tools/move-package/src/source_package/manifest_parser.rs @@ -4,6 +4,7 @@ use crate::{source_package::parsed_manifest as PM, Architecture}; use anyhow::{bail, format_err, Context, Result}; +use move_command_line_common::env::MOVE_HOME; use move_core_types::account_address::{AccountAddress, AccountAddressParseError}; use move_symbol_pool::symbol::Symbol; use std::{ @@ -328,15 +329,7 @@ fn parse_dependency(tval: TV) -> Result { } (None, Some(git)) => { // Look to see if a MOVE_HOME has been set. Otherwise default to $HOME - let move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { - format!( - "{}/.move", - dirs_next::home_dir() - .expect("user's home directory not found") - .to_str() - .unwrap() - ) - }); + let move_home = MOVE_HOME.clone(); let rev_name = match table.remove("rev") { None => bail!("Git revision not supplied for dependency"), Some(r) => Symbol::from( From a591f97bc93bc8f4695ef06eeb28086b38e79406 Mon Sep 17 00:00:00 2001 From: Yao <48658585+0xYao@users.noreply.github.com> Date: Mon, 8 Aug 2022 16:17:07 -0600 Subject: [PATCH 046/169] [move-analyzer] basic function name completion (#338) * [move-analyzer] add primitive types completion * [move-analyzer] specify function kind to completion item We build the "file_functions" map at symbolication, "file_function" is a mapping from the file path to every function declartion inside the file. In the "identifiers" method, we say the text content x is a function if the current file contains a function declaration named x. * [move-analyzer] add file_functions field accessor and replace UseDef with IdentType in FunctionIdentTypeMap * [move-analyzer] add integration test for textDocument/completion * [move-analyzer] fix linting * [move-analyzer] add tests for primitive types completion * [move-analyzer] fix cargo linting * [move-analyzer] remove "signer" from the KEYWORDS const * [move-analyzer] fix comment typo in lsp.test.ts Co-authored-by: Adam Welc Co-authored-by: Adam Welc --- .../editors/code/src/commands/lsp_command.ts | 24 ++++- .../move-analyzer/editors/code/src/main.ts | 1 + .../tests/lsp-demo/sources/Completions.move | 13 +++ .../editors/code/tests/lsp.test.ts | 87 +++++++++++++++++++ .../move-analyzer/src/bin/move-analyzer.rs | 4 +- language/move-analyzer/src/completion.rs | 47 +++++++--- language/move-analyzer/src/symbols.rs | 74 ++++++++++++---- language/move-compiler/src/parser/keywords.rs | 2 + 8 files changed, 217 insertions(+), 35 deletions(-) create mode 100644 language/move-analyzer/editors/code/tests/lsp-demo/sources/Completions.move diff --git a/language/move-analyzer/editors/code/src/commands/lsp_command.ts b/language/move-analyzer/editors/code/src/commands/lsp_command.ts index dbbda4af5e..157551759a 100644 --- a/language/move-analyzer/editors/code/src/commands/lsp_command.ts +++ b/language/move-analyzer/editors/code/src/commands/lsp_command.ts @@ -2,8 +2,11 @@ import type { DocumentSymbolParams, SymbolInformation, DocumentSymbol, + CompletionParams, + CompletionList, + CompletionItem, } from 'vscode-languageclient'; -import { DocumentSymbolRequest, HoverRequest } from 'vscode-languageclient'; +import { DocumentSymbolRequest, HoverRequest, CompletionRequest } from 'vscode-languageclient'; import type { Context } from '../context'; /** @@ -12,8 +15,7 @@ import type { Context } from '../context'; export async function textDocumentDocumentSymbol( context: Readonly, params: DocumentSymbolParams, -) - : Promise { +): Promise { const client = context.getClient(); if (client === undefined) { return Promise.reject(new Error('No language client connected.')); @@ -23,6 +25,22 @@ export async function textDocumentDocumentSymbol( return client.sendRequest(DocumentSymbolRequest.type, params); } +/** + * An LSP command textDocument/completion + */ +export async function textDocumentCompletion( + context: Readonly, + params: CompletionParams, +): Promise { + const client = context.getClient(); + if (client === undefined) { + return Promise.reject(new Error('No language client connected.')); + } + + // Send the request to the language client. + return client.sendRequest(CompletionRequest.type, params); +} + /** * An LSP command textDocument/hover diff --git a/language/move-analyzer/editors/code/src/main.ts b/language/move-analyzer/editors/code/src/main.ts index a219035197..64981a2263 100644 --- a/language/move-analyzer/editors/code/src/main.ts +++ b/language/move-analyzer/editors/code/src/main.ts @@ -75,4 +75,5 @@ export async function activate(extensionContext: Readonly { + return ( + items.find((item) => item.label === fnName && item.kind === CompletionItemKind.Function) !== + undefined + ); +}; + +const isKeywordInCompletionItems = (label: string, items: vscode.CompletionItem[]): boolean => { + return ( + items.find((item) => item.label === label && item.kind === CompletionItemKind.Keyword) !== + undefined + ); +}; + +const PRIMITIVE_TYPES = ['u8', 'u64', 'u128', 'bool', 'vector']; Mocha.suite('LSP', () => { Mocha.test('textDocument/documentSymbol', async () => { @@ -126,6 +143,76 @@ Mocha.suite('LSP', () => { assert.ok(hoverResult); assert.deepStrictEqual((hoverResult.contents as MarkupContent).value, 'Symbols::M3::OtherDocStruct\n\nDocumented struct in another module\n'); + }); + + Mocha.test('textDocument/completion', async () => { + const ext = vscode.extensions.getExtension('move.move-analyzer'); + assert.ok(ext); + + await ext.activate(); // Synchronous waiting for activation to complete + + // 1. get workdir + const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; + + // 2. open doc + const docs = await vscode.workspace.openTextDocument( + path.join(workDir, 'sources/Completions.move'), + ); + await vscode.window.showTextDocument(docs); + + // 3. execute command + const params: lc.CompletionParams = { + textDocument: { + uri: docs.uri.toString(), + }, + position: { + line: 12, + character: 1, + }, + }; + + const items = await vscode.commands.executeCommand>( + 'move-analyzer.textDocumentCompletion', + params, + ); + + assert.ok(items); + + // Items should return all functions defined in the file + assert.strictEqual(isFunctionInCompletionItems('add', items), true); + assert.strictEqual(isFunctionInCompletionItems('subtract', items), true); + assert.strictEqual(isFunctionInCompletionItems('divide', items), true); + + // Items also include all primitive types because they are keywords + PRIMITIVE_TYPES.forEach((primitive) => { + assert.strictEqual(isKeywordInCompletionItems(primitive, items), true); + }); + + const colonParams: lc.CompletionParams = { + textDocument: { + uri: docs.uri.toString(), + }, + // The position of the character ":" + position: { + line: 9, + character: 15, + }, + }; + + const itemsOnColon = await vscode.commands.executeCommand>( + 'move-analyzer.textDocumentCompletion', + colonParams, + ); + + assert.ok(itemsOnColon); + + const keywordsOnColon = itemsOnColon.filter(i => i.kind === CompletionItemKind.Keyword); + // Primitive types are the only keywords returned after inserting the colon + assert.strictEqual(keywordsOnColon.length, PRIMITIVE_TYPES.length); + // Final safety check + PRIMITIVE_TYPES.forEach((primitive) => { + assert.strictEqual(isKeywordInCompletionItems(primitive, keywordsOnColon), true); + }); }); }); diff --git a/language/move-analyzer/src/bin/move-analyzer.rs b/language/move-analyzer/src/bin/move-analyzer.rs index e33bc87eb1..d99f6032f0 100644 --- a/language/move-analyzer/src/bin/move-analyzer.rs +++ b/language/move-analyzer/src/bin/move-analyzer.rs @@ -223,7 +223,9 @@ fn main() { fn on_request(context: &Context, request: &Request) { match request.method.as_str() { - lsp_types::request::Completion::METHOD => on_completion_request(context, request), + lsp_types::request::Completion::METHOD => { + on_completion_request(context, request, &context.symbols.lock().unwrap()) + } lsp_types::request::GotoDefinition::METHOD => { symbols::on_go_to_def_request(context, request, &context.symbols.lock().unwrap()); } diff --git a/language/move-analyzer/src/completion.rs b/language/move-analyzer/src/completion.rs index 5c0b97c89b..6b24da3d4c 100644 --- a/language/move-analyzer/src/completion.rs +++ b/language/move-analyzer/src/completion.rs @@ -2,12 +2,15 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::context::Context; +use crate::{ + context::Context, + symbols::{FunctionIdentTypeMap, Symbols}, +}; use lsp_server::Request; use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, Position}; use move_command_line_common::files::FileHash; use move_compiler::parser::{ - keywords::{BUILTINS, CONTEXTUAL_KEYWORDS, KEYWORDS}, + keywords::{BUILTINS, CONTEXTUAL_KEYWORDS, KEYWORDS, PRIMITIVE_TYPES}, lexer::{Lexer, Tok}, }; use std::collections::HashSet; @@ -31,6 +34,7 @@ fn keywords() -> Vec { KEYWORDS .iter() .chain(CONTEXTUAL_KEYWORDS.iter()) + .chain(PRIMITIVE_TYPES.iter()) .map(|label| { let kind = if label == &"copy" || label == &"move" { CompletionItemKind::Operator @@ -42,6 +46,14 @@ fn keywords() -> Vec { .collect() } +/// Return a list of completion items of Move's primitive types +fn primitive_types() -> Vec { + PRIMITIVE_TYPES + .iter() + .map(|label| completion_item(label, CompletionItemKind::Keyword)) + .collect() +} + /// Return a list of completion items corresponding to each one of Move's builtin functions. fn builtins() -> Vec { BUILTINS @@ -59,7 +71,10 @@ fn builtins() -> Vec { /// server did not initialize with a response indicating it's capable of providing completions. In /// the future, the server should be modified to return semantically valid completion items, not /// simple textual suggestions. -fn identifiers(buffer: &str) -> Vec { +fn identifiers( + buffer: &str, + function_use_def: Option<&FunctionIdentTypeMap>, +) -> Vec { let mut lexer = Lexer::new(buffer, FileHash::new(buffer)); if lexer.advance().is_err() { return vec![]; @@ -85,11 +100,19 @@ fn identifiers(buffer: &str) -> Vec { // The completion item kind "text" indicates that the item is based on simple textual matching, // not any deeper semantic analysis. - let items = ids - .iter() - .map(|label| completion_item(label, CompletionItemKind::Text)) - .collect(); - items + ids.iter() + .map(|label| { + if let Some(fun_data) = function_use_def { + if fun_data.clone().contains_key(&label.to_string()) { + completion_item(label, CompletionItemKind::Function) + } else { + completion_item(label, CompletionItemKind::Text) + } + } else { + completion_item(label, CompletionItemKind::Text) + } + }) + .collect() } /// Returns the token corresponding to the "trigger character" that precedes the user's cursor, @@ -122,7 +145,7 @@ fn get_cursor_token(buffer: &str, position: &Position) -> Option { /// Sends the given connection a response to a completion request. /// /// The completions returned depend upon where the user's cursor is positioned. -pub fn on_completion_request(context: &Context, request: &Request) { +pub fn on_completion_request(context: &Context, request: &Request, symbols: &Symbols) { eprintln!("handling completion request"); let parameters = serde_json::from_value::(request.params.clone()) .expect("could not deserialize completion request"); @@ -148,9 +171,7 @@ pub fn on_completion_request(context: &Context, request: &Request) { let mut items = vec![]; match cursor { Some(Tok::Colon) => { - // If the user's cursor is positioned after a single `:`, do not provide any completion - // items at all -- this is a "mis-fire" of the "trigger character" `:`. - return; + items.extend_from_slice(&primitive_types()); } Some(Tok::Period) | Some(Tok::ColonColon) => { // `.` or `::` must be followed by identifiers, which are added to the completion items @@ -165,7 +186,7 @@ pub fn on_completion_request(context: &Context, request: &Request) { } if let Some(buffer) = &buffer { - let identifiers = identifiers(buffer); + let identifiers = identifiers(buffer, symbols.get_file_functions().get(&path)); items.extend_from_slice(&identifiers); } diff --git a/language/move-analyzer/src/symbols.rs b/language/move-analyzer/src/symbols.rs index 6a2adc5af5..dcb71b13b7 100644 --- a/language/move-analyzer/src/symbols.rs +++ b/language/move-analyzer/src/symbols.rs @@ -210,6 +210,10 @@ pub struct Symbolicator { #[derive(Debug, Clone, Eq, PartialEq)] struct UseDefMap(BTreeMap>); +/// Maps a function name to its usage definition +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct FunctionIdentTypeMap(BTreeMap); + /// Result of the symbolication process pub struct Symbols { /// A map from def locations to all the references (uses) @@ -218,6 +222,8 @@ pub struct Symbols { file_use_defs: BTreeMap, /// A mapping from file hashes to file names file_name_mapping: BTreeMap, + /// A mapping from filePath to function definitions + file_functions: BTreeMap, /// A mapping from filePath to ModuleDefs file_mods: BTreeMap>, } @@ -551,6 +557,20 @@ impl UseDefMap { } } +impl FunctionIdentTypeMap { + fn new() -> Self { + Self(BTreeMap::new()) + } + + fn insert(&mut self, key: String, val: IdentType) { + self.0.entry(key).or_insert_with(|| val); + } + + pub fn contains_key(self, key: &String) -> bool { + self.0.contains_key(key) + } +} + impl Symbols { pub fn merge(&mut self, other: Self) { for (k, v) in other.references { @@ -561,8 +581,13 @@ impl Symbols { } self.file_use_defs.extend(other.file_use_defs); self.file_name_mapping.extend(other.file_name_mapping); + self.file_functions.extend(other.file_functions); self.file_mods.extend(other.file_mods); } + + pub fn get_file_functions(&self) -> &BTreeMap { + &self.file_functions + } } impl Symbolicator { @@ -698,21 +723,31 @@ impl Symbolicator { let mut references = BTreeMap::new(); let mut file_use_defs = BTreeMap::new(); + let mut file_functions = BTreeMap::new(); + let mut function_ident_type = FunctionIdentTypeMap::new(); + for (pos, module_ident, module_def) in modules { let mut use_defs = mod_use_defs.remove(module_ident).unwrap(); symbolicator.current_mod = Some(sp(pos, *module_ident)); - symbolicator.mod_symbols(module_def, &mut references, &mut use_defs); + symbolicator.mod_symbols( + module_def, + &mut references, + &mut use_defs, + &mut function_ident_type, + ); let fpath = match source_files.get(&pos.file_hash()) { Some((p, _)) => p, None => continue, }; + let fpath_buffer = dunce::canonicalize(fpath.as_str()) + .unwrap_or_else(|_| PathBuf::from(fpath.as_str())); + + file_functions.insert(fpath_buffer.to_owned(), function_ident_type.clone()); + file_use_defs - .entry( - dunce::canonicalize(fpath.as_str()) - .unwrap_or_else(|_| PathBuf::from(fpath.as_str())), - ) + .entry(fpath_buffer) .or_insert_with(UseDefMap::new) .extend(use_defs.elements()); } @@ -722,6 +757,7 @@ impl Symbolicator { file_use_defs, file_name_mapping, file_mods, + file_functions, }; eprintln!("get_symbols load complete"); @@ -736,6 +772,7 @@ impl Symbolicator { references: BTreeMap::new(), file_name_mapping: BTreeMap::new(), file_mods: BTreeMap::new(), + file_functions: BTreeMap::new(), } } @@ -867,6 +904,7 @@ impl Symbolicator { mod_def: &ModuleDefinition, references: &mut BTreeMap>, use_defs: &mut UseDefMap, + function_ident_type: &mut FunctionIdentTypeMap, ) { for (pos, name, fun) in &mod_def.functions { // enter self-definition for function name (unwrap safe - done when inserting def) @@ -895,21 +933,21 @@ impl Symbolicator { .collect(), ); let ident_type_def = self.ident_type_def_loc(&use_type); - use_defs.insert( - name_start.line, - UseDef::new( - references, - pos.file_hash(), - name_start, - pos.file_hash(), - name_start, - name, - use_type, - ident_type_def, - doc_string, - ), + let use_def = UseDef::new( + references, + pos.file_hash(), + name_start, + pos.file_hash(), + name_start, + name, + use_type.clone(), + ident_type_def, + doc_string, ); + + use_defs.insert(name_start.line, use_def); self.fun_symbols(fun, references, use_defs); + function_ident_type.insert(name.to_string(), use_type); } for (pos, name, c) in &mod_def.constants { diff --git a/language/move-compiler/src/parser/keywords.rs b/language/move-compiler/src/parser/keywords.rs index ceaff4dd92..6e4cf8c181 100644 --- a/language/move-compiler/src/parser/keywords.rs +++ b/language/move-compiler/src/parser/keywords.rs @@ -65,6 +65,8 @@ pub const CONTEXTUAL_KEYWORDS: &[&str] = &[ "with", ]; +pub const PRIMITIVE_TYPES: &[&str] = &["u8", "u64", "u128", "bool", "vector"]; + pub const BUILTINS: &[&str] = &[ "assert", "borrow_global", From 74f8741e9d3e9e893149a7bd2fab04f8ed1c2037 Mon Sep 17 00:00:00 2001 From: Abner Chen Date: Tue, 9 Aug 2022 11:05:25 +0800 Subject: [PATCH 047/169] Fix toml in cli readme (#361) --- language/tools/move-cli/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/language/tools/move-cli/README.md b/language/tools/move-cli/README.md index 093a411f5b..7ef37192f0 100644 --- a/language/tools/move-cli/README.md +++ b/language/tools/move-cli/README.md @@ -125,11 +125,11 @@ directory: ```toml [addresses] -Std = "0x1" # Specify and assign 0x1 to the named address "Std" +std = "0x1" # Specify and assign 0x1 to the named address "std" [dependencies] -MoveNursery = { git = "https://github.com/move-language/move.git", subdir = "language/move-stdlib/nursery", rev = "d45f20a" } -# ^ ^ ^ ^ +MoveNursery = { git = "https://github.com/move-language/move.git", subdir = "language/move-stdlib/nursery", rev = "main" } +# ^ ^ ^ ^ # Git dependency Git clone URL Subdir under git repo (optional) Git revision to use ``` From a33095797393fbb9851a9e2905ecba36cd1bab30 Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Tue, 9 Aug 2022 11:09:06 +0800 Subject: [PATCH 048/169] migrate Move Book of Chinese version from MoveCC (#359) --- .../book/translations/move-book-zh/.gitignore | 1 + .../book/translations/move-book-zh/README.md | 32 + .../book/translations/move-book-zh/book.toml | 6 + .../translations/move-book-zh/src/SUMMARY.md | 45 + .../move-book-zh/src/abilities.md | 316 +++++++ .../move-book-zh/src/abort-and-assert.md | 258 ++++++ .../translations/move-book-zh/src/address.md | 100 ++ .../translations/move-book-zh/src/bool.md | 44 + .../move-book-zh/src/coding-conventions.md | 114 +++ .../move-book-zh/src/conditionals.md | 79 ++ .../move-book-zh/src/constants.md | 140 +++ .../move-book-zh/src/creating-coins.md | 5 + .../translations/move-book-zh/src/equality.md | 190 ++++ .../translations/move-book-zh/src/friends.md | 162 ++++ .../move-book-zh/src/functions.md | 616 ++++++++++++ .../translations/move-book-zh/src/generics.md | 566 +++++++++++ .../src/global-storage-operators.md | 305 ++++++ .../src/global-storage-structure.md | 21 + .../translations/move-book-zh/src/integers.md | 176 ++++ .../move-book-zh/src/introduction.md | 49 + .../translations/move-book-zh/src/loops.md | 217 +++++ .../move-book-zh/src/modules-and-scripts.md | 163 ++++ .../translations/move-book-zh/src/overview.md | 200 ++++ .../translations/move-book-zh/src/packages.md | 361 ++++++++ .../move-book-zh/src/references.md | 277 ++++++ .../translations/move-book-zh/src/signer.md | 93 ++ .../move-book-zh/src/standard-library.md | 702 ++++++++++++++ .../move-book-zh/src/structs-and-resources.md | 593 ++++++++++++ .../translations/move-book-zh/src/tuples.md | 162 ++++ .../move-book-zh/src/unit-testing.md | 376 ++++++++ .../translations/move-book-zh/src/uses.md | 416 +++++++++ .../move-book-zh/src/variables.md | 875 ++++++++++++++++++ .../translations/move-book-zh/src/vector.md | 209 +++++ 33 files changed, 7869 insertions(+) create mode 100644 language/documentation/book/translations/move-book-zh/.gitignore create mode 100644 language/documentation/book/translations/move-book-zh/README.md create mode 100644 language/documentation/book/translations/move-book-zh/book.toml create mode 100644 language/documentation/book/translations/move-book-zh/src/SUMMARY.md create mode 100644 language/documentation/book/translations/move-book-zh/src/abilities.md create mode 100644 language/documentation/book/translations/move-book-zh/src/abort-and-assert.md create mode 100644 language/documentation/book/translations/move-book-zh/src/address.md create mode 100644 language/documentation/book/translations/move-book-zh/src/bool.md create mode 100644 language/documentation/book/translations/move-book-zh/src/coding-conventions.md create mode 100644 language/documentation/book/translations/move-book-zh/src/conditionals.md create mode 100644 language/documentation/book/translations/move-book-zh/src/constants.md create mode 100644 language/documentation/book/translations/move-book-zh/src/creating-coins.md create mode 100644 language/documentation/book/translations/move-book-zh/src/equality.md create mode 100644 language/documentation/book/translations/move-book-zh/src/friends.md create mode 100644 language/documentation/book/translations/move-book-zh/src/functions.md create mode 100644 language/documentation/book/translations/move-book-zh/src/generics.md create mode 100644 language/documentation/book/translations/move-book-zh/src/global-storage-operators.md create mode 100644 language/documentation/book/translations/move-book-zh/src/global-storage-structure.md create mode 100644 language/documentation/book/translations/move-book-zh/src/integers.md create mode 100644 language/documentation/book/translations/move-book-zh/src/introduction.md create mode 100644 language/documentation/book/translations/move-book-zh/src/loops.md create mode 100644 language/documentation/book/translations/move-book-zh/src/modules-and-scripts.md create mode 100644 language/documentation/book/translations/move-book-zh/src/overview.md create mode 100644 language/documentation/book/translations/move-book-zh/src/packages.md create mode 100644 language/documentation/book/translations/move-book-zh/src/references.md create mode 100644 language/documentation/book/translations/move-book-zh/src/signer.md create mode 100644 language/documentation/book/translations/move-book-zh/src/standard-library.md create mode 100644 language/documentation/book/translations/move-book-zh/src/structs-and-resources.md create mode 100644 language/documentation/book/translations/move-book-zh/src/tuples.md create mode 100644 language/documentation/book/translations/move-book-zh/src/unit-testing.md create mode 100644 language/documentation/book/translations/move-book-zh/src/uses.md create mode 100644 language/documentation/book/translations/move-book-zh/src/variables.md create mode 100644 language/documentation/book/translations/move-book-zh/src/vector.md diff --git a/language/documentation/book/translations/move-book-zh/.gitignore b/language/documentation/book/translations/move-book-zh/.gitignore new file mode 100644 index 0000000000..7585238efe --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/.gitignore @@ -0,0 +1 @@ +book diff --git a/language/documentation/book/translations/move-book-zh/README.md b/language/documentation/book/translations/move-book-zh/README.md new file mode 100644 index 0000000000..756fb14289 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/README.md @@ -0,0 +1,32 @@ +# Move Book 中文版 + +区块链技术的发展经历了两个阶段,比特币(BTC)开启了*区块链1.0时代*,以太坊(ETH)开启了*区块链2.0时代*。 +以太坊的出现为区块链带来了*智能合约*这一关键技术,让区块链不只停留在记账这一单的目的,而是带来更多的应用拓展性。 +遗憾的是,智能合约如同一把双刃剑,在带来众多丰富功能拓展的同时,也容易让智能合约开发者无意间引入不安全的代码,让链的资产受到威胁。 + +编写简单、安全、易部署的智能合约应该是*区块链3.0时代*应该关注的重点,**面向资源编程**的 [Move 语言](https://github.com/move-language/move),无疑给这个问题提供了一个很好的解决方案。 + +本书是 [Move Book](https://move-language.github.io/move/) 的中文版。 + +## 快速开始 + +本书使用 [mdBook](https://rust-lang.github.io/mdBook/) 构建。 + +1. 使用 Cargo 安装 mdBook: + +```shell +cargo install mdbook +``` + +2. 下载 + +```shell +git clone https://github.com/move-cc/move-book-zh.git +``` + +3. 构建并预览 + +```shell +cd move-book-zh +mdbook serve --open +``` diff --git a/language/documentation/book/translations/move-book-zh/book.toml b/language/documentation/book/translations/move-book-zh/book.toml new file mode 100644 index 0000000000..06baef605d --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["Joe Chen"] +language = "en" +multilingual = false +src = "src" +title = "Move Book 中文版" diff --git a/language/documentation/book/translations/move-book-zh/src/SUMMARY.md b/language/documentation/book/translations/move-book-zh/src/SUMMARY.md new file mode 100644 index 0000000000..1ed9cbc12e --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/SUMMARY.md @@ -0,0 +1,45 @@ +# The Move Programming Language + +[Introduction](introduction.md) + +## Getting Started + +- [Modules and Scripts](modules-and-scripts.md) +- [Move Tutorial](creating-coins.md) + +## Primitive Types + +- [Integers](integers.md) +- [Bool](bool.md) +- [Address](address.md) +- [Vector](vector.md) +- [Signer](signer.md) +- [References](references.md) +- [Tuples and Unit](tuples.md) + +## Basic Concepts + +- [Local Variables and Scopes](variables.md) +- [Equality](equality.md) +- [Abort and Assert](abort-and-assert.md) +- [Conditionals](conditionals.md) +- [While and Loop](loops.md) +- [Functions](functions.md) +- [Structs and Resources](structs-and-resources.md) +- [Constants](constants.md) +- [Generics](generics.md) +- [Type Abilities](abilities.md) +- [Uses and Aliases](uses.md) +- [Friends](friends.md) +- [Packages](packages.md) +- [Unit Tests](unit-testing.md) + +## Global Storage + +- [Global Storage Structure](global-storage-structure.md) +- [Global Storage Operators](global-storage-operators.md) + +## Reference + +- [Standard Library](standard-library.md) +- [Coding Conventions](coding-conventions.md) diff --git a/language/documentation/book/translations/move-book-zh/src/abilities.md b/language/documentation/book/translations/move-book-zh/src/abilities.md new file mode 100644 index 0000000000..9db855beae --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/abilities.md @@ -0,0 +1,316 @@ +# Abilities + +Abilities are a typing feature in Move that control what actions are permissible for values of a given type. This system grants fine grained control over the "linear" typing behavior of values, as well as if and how values are used in global storage. This is implemented by gating access to certain bytecode instructions so that for a value to be used with the bytecode instruction, it must have the ability required (if one is required at all—not every instruction is gated by an ability). +# 能力 +能力是 Move 中的一种输入功能,用于控制对给定类型的值允许哪些操作。该系统对值的“线性”类型行为以及值是否以及如何在全局存储中使用提供细粒度控制。这是通过对某些字节码指令的访问进行门控来实现的,因此对于要与字节码指令一起使用的值,它必须具有所需的能力(如果完全需要——不是每条指令都由能力门控)。 + + + +## The Four Abilities + +The four abilities are: +## 四种能力 +四种能力分别是: + +* [`copy`](#copy) + * Allows values of types with this ability to be copied. + * 允许复制具有此能力的类型的值。 +* [`drop`](#drop) + * Allows values of types with this ability to be popped/dropped. + * 允许弹出/删除具有此能力的类型的值。 +* [`store`](#store) + * Allows values of types with this ability to exist inside a struct in global storage. + * 允许具有这种能力的类型的值存在于全局存储的结构中。 +* [`key`](#key) + * Allows the type to serve as a key for global storage operations. + * 允许该类型作为全局存储操作的键。 + +### `copy` + +The `copy` ability allows values of types with that ability to be copied. It gates the ability to copy values out of local variables with the [`copy`](./variables.md#move-and-copy) operator and to copy values via references with [dereference `*e`](./references.md#reading-and-writing-through-references). + +If a value has `copy`, all values contained inside of that value have `copy`. + +复制能力允许复制具有该能力的类型的值。它控制了使用复制运算符从局部变量中复制值以及通过取消引用 `*e` 的引用复制值的能力。 + +如果一个值有副本,则该值内包含的所有值都有副本。 + +### `drop` + +The `drop` ability allows values of types with that ability to be dropped. By dropped, we mean that value is not transferred and is effectively destroyed as the Move program executes. As such, this ability gates the ability to ignore values in a multitude of locations, including: +* not using the value in a local variable or parameter +* not using the value in a [sequence via `;`](./variables.md#expression-blocks) +* overwriting values in variables in [assignments](./variables.md#assignments) +* overwriting values via references when [writing `*e1 = e2`](./references.md#reading-and-writing-through-references). + +If a value has `drop`, all values contained inside of that value have `drop`. + +丢弃能力允许丢弃具有该能力的类型的值。被丢弃,我们的意思是价值没有被转移,并且在 Move 程序执行时被有效地销毁。因此,此能力限制了在多个位置忽略值的能力,包括: + +* 不使用局部变量或参数中的值 +* 不使用序列中的值; +* 覆盖赋值变量中的值 +* 写入 `*e1 = e2` 时通过引用覆盖值。 + +如果一个值下降,则该值内包含的所有值都下降。 + +### `store` + +The `store` ability allows values of types with this ability to exist inside of a struct (resource) in global storage, *but* not necessarily as a top-level resource in global storage. This is the only ability that does not directly gate an operation. Instead it gates the existence in global storage when used in tandem with `key`. + +If a value has `store`, all values contained inside of that value have `store` + +存储能力允许具有这种能力的类型的值存在于全局存储中的结构(资源)内部,但不一定作为全局存储中的顶级资源。这是唯一不直接控制操作的能力。相反,当与 key 一起使用时,它会限制全局存储中的存在。 + +如果一个值具有存储,则该值内包含的所有值都具有存储 + +### `key` + +The `key` ability allows the type to serve as a key for [global storage operations](./global-storage-operators.md). It gates all global storage operations, so in order for a type to be used with `move_to`, `borrow_global`, `move_from`, etc., the type must have the `key` ability. Note that the operations still must be used in the module where the `key` type is defined (in a sense, the operations are private to the defining module). + +If a value has `key`, all values contained inside of that value have `store`. This is the only ability with this sort of asymmetry. + +密钥能力允许该类型作为全局存储操作的密钥。它对所有全局存储操作进行门控,因此要使类型与 move_to、borrow_global、move_from 等一起使用,该类型必须具有 key 能力。请注意,这些操作仍然必须在定义密钥类型的模块中使用(从某种意义上说,这些操作是定义模块的私有)。 + +如果一个值有键,则包含在该值内的所有值都有存储。这是唯一具有这种不对称性的能力。 + +## Builtin Types + +Most primitive, builtin types have `copy`, `drop`, and `store` with the exception of `signer`, which just has `store` + +* `bool`, `u8`, `u64`, `u128`, and `address` all have `copy`, `drop`, and `store`. +* `signer` has `drop` + * Cannot be copied and cannot be put into global storage +* `vector` may have `copy`, `drop`, and `store` depending on the abilities of `T`. + * See [Conditional Abilities and Generic Types](#conditional-abilities-and-generic-types) for more details. +* Immutable references `&` and mutable references `&mut` both have `copy` and `drop`. + * This refers to copying and dropping the reference itself, not what they refer to. + * References cannot appear in global storage, hence they do not have `store`. + +None of the primitive types have `key`, meaning none of them can be used directly with the [global storage operations](./global-storage-operators.md). +## 内置类型 +大多数原始的内置类型都有复制、删除和存储,但签名者除外,它只有存储 + +* bool, u8, u64, u128, 和address都有copy、drop和store。 +* 签名者有下降 + * 无法复制,无法放入全局存储 +* 根据 T 的能力,向量 T 可能具有复制、删除和存储。 + * 有关更多详细信息,请参阅条件能力和通用类型。 +* 不可变引用 & 和可变引用 &mut 都有复制和删除。 + * 这是指复制和删除引用本身,而不是它们所指的内容。 + * 引用不能出现在全局存储中,因此它们没有存储。 +所有原始类型都没有键,这意味着它们都不能直接用于全局存储操作。 + +## Annotating Structs + +To declare that a `struct` has an ability, it is declared with `has ` after the struct name but before the fields. For example: +## 注释结构 +要声明结构具有能力,请在结构名称之后但在字段之前使用具有能力来声明它。例如: + +```move +struct Ignorable has drop { f: u64 } +struct Pair has copy, drop, store { x: u64, y: u64 } +``` + +In this case: `Ignorable` has the `drop` ability. `Pair` has `copy`, `drop`, and `store`. + + +All of these abilities have strong guarantees over these gated operations. The operation can be performed on the value only if it has that ability; even if the value is deeply nested inside of some other collection! + +As such: when declaring a struct’s abilities, certain requirements are placed on the fields. All fields must satisfy these constraints. These rules are necessary so that structs satisfy the reachability rules for the abilities given above. If a struct is declared with the ability... + +* `copy`, all fields must have `copy`. +* `drop`, all fields must have `drop`. +* `store`, all fields must have `store`. +* `key`, all fields must have `store`. + * `key` is the only ability currently that doesn’t require itself. + +For example: +在这种情况下: Ignorable 具有丢弃能力。 Pair 具有复制、删除和存储功能。 + +所有这些能力对这些门控操作都有强有力的保证。只有具有该能力,才能对值执行操作;即使该值深深嵌套在其他集合中! + +因此:在声明结构的能力时,对字段提出了某些要求。所有字段都必须满足这些约束。这些规则是必要的,以便结构满足上述功能的可达性规则。如果一个结构被声明为具有能力...... + +* copy,所有字段都必须有副本。 +* drop,所有字段都必须有drop。 +* store,所有字段都必须有store。 +* key,所有字段都必须有存储。 + * key是目前唯一不需要自己的能力。 +例如: + +```move +// A struct without any abilities +struct NoAbilities {} + +struct WantsCopy has copy { + f: NoAbilities, // ERROR 'NoAbilities' does not have 'copy' +} +``` + +and similarly: +同样: + +```move +// A struct without any abilities +struct NoAbilities {} + +struct MyResource has key { + f: NoAbilities, // Error 'NoAbilities' does not have 'store' +} +``` + +## Conditional Abilities and Generic Types + +When abilities are annotated on a generic type, not all instances of that type are guaranteed to have that ability. Consider this struct declaration: +## 条件能力和通用类型 +在泛型类型上注释能力时,并非该类型的所有实例都保证具有该能力。考虑这个结构声明: + +``` +struct Cup has copy, drop, store, key { item: T } +``` + +It might be very helpful if `Cup` could hold any type, regardless of its abilities. The type system can *see* the type parameter, so it should be able to remove abilities from `Cup` if it *sees* a type parameter that would violate the guarantees for that ability. + +This behavior might sound a bit confusing at first, but it might be more understandable if we think about collection types. We could consider the builtin type `vector` to have the following type declaration: +如果 Cup 可以容纳任何类型,无论其能力如何,这可能会非常有帮助。类型系统可以看到类型参数,因此如果它看到一个类型参数会违反该能力的保证,它应该能够从 Cup 中删除能力。 + +这种行为一开始可能听起来有点令人困惑,但如果我们考虑一下集合类型,它可能会更容易理解。我们可以考虑内置类型向量具有以下类型声明: + +``` +vector has copy, drop, store; +``` + +We want `vector`s to work with any type. We don't want separate `vector` types for different abilities. So what are the rules we would want? Precisely the same that we would want with the field rules above. So, it would be safe to copy a `vector` value only if the inner elements can be copied. It would be safe to ignore a `vector` value only if the inner elements can be ignored/dropped. And, it would be safe to put a `vector` in global storage only if the inner elements can be in global storage. + +To have this extra expressiveness, a type might not have all the abilities it was declared with depending on the instantiation of that type; instead, the abilities a type will have depends on both its declaration **and** its type arguments. For any type, type parameters are pessimistically assumed to be used inside of the struct, so the abilities are only granted if the type parameters meet the requirements described above for fields. Taking `Cup` from above as an example: + +* `Cup` has the ability `copy` only if `T` has `copy`. +* It has `drop` only if `T` has `drop`. +* It has `store` only if `T` has `store`. +* It has `key` only if `T` has `store`. + +Here are examples for this conditional system for each ability: + +我们希望向量适用于任何类型。我们不希望针对不同的能力使用不同的向量类型。那么我们想要的规则是什么?与上面的字段规则完全相同。因此,仅当可以复制内部元素时,复制向量值才是安全的。仅当可以忽略/删除内部元素时,忽略向量值才是安全的。而且,仅当内部元素可以在全局存储中时,将向量放入全局存储中才是安全的。 + +为了拥有这种额外的表现力,一个类型可能不具备它声明的所有能力,具体取决于该类型的实例化;相反,一个类型的能力取决于它的声明和它的类型参数。对于任何类型,类型参数都被悲观地假定为在结构内部使用,因此只有在类型参数满足上述字段要求时才授予能力。以上面的 Cup 为例: + +* 只有 T 有副本,Cup 才有能力副本。 +* 只有当 T 有下降时它才有下降。 +* 只有当 T 有存储时它才有存储。 +* 只有当 T 有存储时它才有密钥。 + +以下是每个能力的条件系统的示例: + +### Example: conditional `copy` + +``` +struct NoAbilities {} +struct S has copy, drop { f: bool } +struct Cup has copy, drop, store { item: T } + +fun example(c_x: Cup, c_s: Cup) { + // Valid, 'Cup' has 'copy' because 'u64' has 'copy' + let c_x2 = copy c_x; + // Valid, 'Cup' has 'copy' because 'S' has 'copy' + let c_s2 = copy c_s; +} + +fun invalid(c_account: Cup, c_n: Cup) { + // Invalid, 'Cup' does not have 'copy'. + // Even though 'Cup' was declared with copy, the instance does not have 'copy' + // because 'signer' does not have 'copy' + let c_account2 = copy c_account; + // Invalid, 'Cup' does not have 'copy' + // because 'NoAbilities' does not have 'copy' + let c_n2 = copy c_n; +} +``` + +### Example: conditional `drop` + +``` +struct NoAbilities {} +struct S has copy, drop { f: bool } +struct Cup has copy, drop, store { item: T } + +fun unused() { + Cup { item: true }; // Valid, 'Cup' has 'drop' + Cup { item: S { f: false }}; // Valid, 'Cup' has 'drop' +} + +fun left_in_local(c_account: Cup): u64 { + let c_b = Cup { item: true }; + let c_s = Cup { item: S { f: false }}; + // Valid return: 'c_account', 'c_b', and 'c_s' have values + // but 'Cup', 'Cup', and 'Cup' have 'drop' + 0 +} + +fun invalid_unused() { + // Invalid, Cannot ignore 'Cup' because it does not have 'drop'. + // Even though 'Cup' was declared with 'drop', the instance does not have 'drop' + // because 'NoAbilities' does not have 'drop' + Cup { item: NoAbilities {}}; +} + +fun invalid_left_in_local(): u64 { + let n = Cup { item: NoAbilities {}}; + // Invalid return: 'c_n' has a value + // and 'Cup' does not have 'drop' + 0 +} +``` + +### Example: conditional `store` + +``` +struct Cup has copy, drop, store { item: T } + +// 'MyInnerResource' is declared with 'store' so all fields need 'store' +struct MyInnerResource has store { + yes: Cup, // Valid, 'Cup' has 'store' + // no: Cup, Invalid, 'Cup' does not have 'store' +} + +// 'MyResource' is declared with 'key' so all fields need 'store' +struct MyResource has key { + yes: Cup, // Valid, 'Cup' has 'store' + inner: Cup, // Valid, 'Cup' has 'store' + // no: Cup, Invalid, 'Cup' does not have 'store' +} +``` + +### Example: conditional `key` + +``` +struct NoAbilities {} +struct MyResource has key { f: T } + +fun valid(account: &signer) acquires MyResource { + let addr = signer::address_of(account); + // Valid, 'MyResource' has 'key' + let has_resource = exists>(addr); + if (!has_resource) { + // Valid, 'MyResource' has 'key' + move_to(account, MyResource { f: 0 }) + }; + // Valid, 'MyResource' has 'key' + let r = borrow_global_mut>(addr) + r.f = r.f + 1; +} + +fun invalid(account: &signer) { + // Invalid, 'MyResource' does not have 'key' + let has_it = exists>(addr); + // Invalid, 'MyResource' does not have 'key' + let NoAbilities {} = move_from(addr); + // Invalid, 'MyResource' does not have 'key' + move_to(account, NoAbilities {}); + // Invalid, 'MyResource' does not have 'key' + borrow_global(addr); +} +``` diff --git a/language/documentation/book/translations/move-book-zh/src/abort-and-assert.md b/language/documentation/book/translations/move-book-zh/src/abort-and-assert.md new file mode 100644 index 0000000000..1d6505522b --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/abort-and-assert.md @@ -0,0 +1,258 @@ +# Abort and Assert + +[`return`](./functions.md) and `abort` are two control flow constructs that end execution, one for +the current function and one for the entire transaction. + +More information on [`return` can be found in the linked section](./functions.md) +# 中止和断言 +return 和 abort 是结束执行的两种控制流结构,一种用于当前函数,一种用于整个事务。 + +有关退货的更多信息,请参见链接部分 + +## `abort` + +`abort` is an expression that takes one argument: an **abort code** of type `u64`. For example: +## 中止 +abort 是一个带有一个参数的表达式:u64 类型的中止代码。例如: + +```move +abort 42 +``` + +The `abort` expression halts execution the current function and reverts all changes made to global +state by the current transaction. There is no mechanism for "catching" or otherwise handling an +`abort`. + +Luckily, in Move transactions are all or nothing, meaning any changes to global storage are made all +at once only if the transaction succeeds. Because of this transactional commitment of changes, after +an abort there is no need to worry about backing out changes. While this approach is lacking in +flexibility, it is incredibly simple and predictable. + +Similar to [`return`](./functions.md), `abort` is useful for exiting control flow when some +condition cannot be met. + +In this example, the function will pop two items off of the vector, but will abort early if the +vector does not have two items + +abort 表达式停止执行当前函数并恢复当前事务对全局状态所做的所有更改。没有“捕获”或以其他方式处理中止的机制。 + +幸运的是,在 Move 中,事务是全有或全无,这意味着只有在事务成功时才会对全局存储进行任何更改。由于更改的这种事务性承诺,在中止之后无需担心撤销更改。虽然这种方法缺乏灵活性,但它非常简单且可预测。 + +与 return 类似,abort 对于在某些条件无法满足时退出控制流很有用。 + +在此示例中,该函数将从向量中弹出两个项目,但如果向量没有两个项目,该函数将提前中止 + +```move= +use std::vector; +fun pop_twice(v: &mut vector): (T, T) { + if (vector::length(v) < 2) abort 42; + + (vector::pop_back(v), vector::pop_back(v)) +} +``` + +This is even more useful deep inside a control-flow construct. For example, this function checks +that all numbers in the vector are less than the specified `bound`. And aborts otherwise + +这在控制流结构的深处甚至更有用。例如,此函数检查向量中的所有数字是否小于指定的界限。否则中止 + +```move= +use std::vector; +fun check_vec(v: &vector, bound: u64) { + let i = 0; + let n = vector::length(v); + while (i < n) { + let cur = *vector::borrow(v, i); + if (cur > bound) abort 42; + i = i + 1; + } +} +``` + +### `assert` + +`assert` is a builtin, macro-like operation provided by the Move compiler. It takes two arguments, a +condition of type `bool` and a code of type `u64` + +### 断言 +assert 是 Move 编译器提供的内置的类似宏的操作。它有两个参数,一个 bool 类型的条件和一个 u64 类型的代码 + +```move +assert!(condition: bool, code: u64) +``` + +Since the operation is a macro, it must be invoked with the `!`. This is to convey that the +arguments to `assert` are call-by-expression. In other words, `assert` is not a normal function and +does not exist at the bytecode level. It is replaced inside the compiler with + +由于该操作是一个宏,因此必须使用 ! 调用它。这是为了传达断言的参数是按表达式调用的。换句话说,assert 不是一个普通的函数,在字节码级别是不存在的。它在编译器内部被替换为 + +```move +if (condition) () else abort code +``` + +`assert` is more commonly used than just `abort` by itself. The `abort` examples above can be +rewritten using `assert` + +assert 比 abort 本身更常用。上面的中止示例可以使用 assert 重写 + +```move= +use std::vector; +fun pop_twice(v: &mut vector): (T, T) { + assert!(vector::length(v) >= 2, 42); // Now uses 'assert' + + (vector::pop_back(v), vector::pop_back(v)) +} +``` + +and + +```move= +use std::vector; +fun check_vec(v: &vector, bound: u64) { + let i = 0; + let n = vector::length(v); + while (i < n) { + let cur = *vector::borrow(v, i); + assert!(cur <= bound, 42); // Now uses 'assert' + i = i + 1; + } +} +``` + +Note that because the operation is replaced with this `if-else`, the argument for the `code` is not +always evaluated. For example: + +请注意,由于该操作被替换为 if-else,因此并不总是评估代码的参数。例如: + +```move +assert!(true, 1 / 0) +``` + +Will not result in an arithmetic error, it is equivalent to + +不会导致算术错误,相当于 + +```move +if (true) () else (1 / 0) +``` + +So the arithmetic expression is never evaluated! + +所以算术表达式永远不会被评估! + +### Abort codes in the Move VM + +When using `abort`, it is important to understand how the `u64` code will be used by the VM. + +Normally, after successful execution, the Move VM produces a change-set for the changes made to +global storage (added/removed resources, updates to existing resources, etc). + +If an `abort` is reached, the VM will instead indicate an error. Included in that error will be two +pieces of information: + +- The module that produced the abort (address and name) +- The abort code. + +For example +### Move VM 中的中止代码 +使用 abort 时,了解 VM 将如何使用 u64 代码非常重要。 + +通常,在成功执行后,Move VM 会为对全局存储所做的更改(添加/删除资源、更新现有资源等)生成一个更改集。 + +如果达到中止,VM 将改为指示错误。该错误中包含两条信息: + +产生中止的模块(地址和名称) +中止代码。 +例如 + +```move= +address 0x2 { +module example { + public fun aborts() { + abort 42 + } +} +} + +script { + fun always_aborts() { + 0x2::example::aborts() + } +} +``` + +If a transaction, such as the script `always_aborts` above, calls `0x2::example::aborts`, the VM +would produce an error that indicated the module `0x2::example` and the code `42`. + +This can be useful for having multiple aborts being grouped together inside a module. + +In this example, the module has two separate error codes used in multiple functions + +如果事务(例如上面的脚本 always_aborts)调用 0x2::example::aborts,VM 将产生一个错误,指示模块 0x2::example 和代码 42。 + +这对于在一个模块内将多个中止组合在一起很有用。 + +在此示例中,模块有两个单独的错误代码,用于多个功能 + +```move= +address 0x42 { +module example { + + use std::vector; + + const EMPTY_VECTOR: u64 = 0; + const INDEX_OUT_OF_BOUNDS: u64 = 1; + + // move i to j, move j to k, move k to i + public fun rotate_three(v: &mut vector, i: u64, j: u64, k: u64) { + let n = vector::length(v); + assert!(n > 0, EMPTY_VECTOR); + assert!(i < n, INDEX_OUT_OF_BOUNDS); + assert!(j < n, INDEX_OUT_OF_BOUNDS); + assert!(k < n, INDEX_OUT_OF_BOUNDS); + + vector::swap(v, i, k); + vector::swap(v, j, k); + } + + public fun remove_twice(v: &mut vector, i: u64, j: u64): (T, T) { + let n = vector::length(v); + assert!(n > 0, EMPTY_VECTOR); + assert!(i < n, INDEX_OUT_OF_BOUNDS); + assert!(j < n, INDEX_OUT_OF_BOUNDS); + assert!(i > j, INDEX_OUT_OF_BOUNDS); + + (vector::remove(v, i), vector::remove(v, j)) + } +} +} +``` + +## The type of `abort` + +The `abort i` expression can have any type! This is because both constructs break from the normal +control flow, so they never need to evaluate to the value of that type. + +The following are not useful, but they will type check +## 中止类型 +abort i 表达式可以有任何类型!这是因为这两种构造都脱离了正常的控制流,因此它们永远不需要评估该类型的值。 + +以下没有用,但它们会键入检查 + +```move +let y: address = abort 0; +``` + +This behavior can be helpful in situations where you have a branching instruction that produces a +value on some branches, but not all. For example: + +在您有一个分支指令在某些分支上产生值的情况下,这种行为可能会有所帮助,但不是全部。例如: + +```move +let b = + if (x == 0) false + else if (x == 1) true + else abort 42; +// ^^^^^^^^ `abort 42` has type `bool` +``` diff --git a/language/documentation/book/translations/move-book-zh/src/address.md b/language/documentation/book/translations/move-book-zh/src/address.md new file mode 100644 index 0000000000..104c5c1b07 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/address.md @@ -0,0 +1,100 @@ +# Address + +`address` is a built-in type in Move that is used to represent locations (sometimes called accounts) in global storage. An `address` value is a 128-bit (16 byte) identifier. At a given address, two things can be stored: [Modules](./modules-and-scripts.md) and [Resources](./structs-and-resources.md). + +Although an `address` is a 128 bit integer under the hood, Move addresses are intentionally opaque---they cannot be created from integers, they do not support arithmetic operations, and they cannot be modified. Even though there might be interesting programs that would use such a feature (e.g., pointer arithmetic in C fills a similar niche), Move does not allow this dynamic behavior because it has been designed from the ground up to support static verification. + +You can use runtime address values (values of type `address`) to access resources at that address. You *cannot* access modules at runtime via address values. +# 地址 +address 是 Move 中的内置类型,用于表示全局存储中的位置(有时称为帐户)。地址值是一个 128 位(16 字节)的标识符。在给定的地址,可以存储两件事:模块和资源。 + +尽管地址实际上是一个 128 位整数,但移动地址是故意不透明的——它们不能从整数创建,它们不支持算术运算,也不能修改。尽管可能有一些有趣的程序会使用这种特性(例如,C 中的指针算法填补了类似的利基),但 Move 不允许这种动态行为,因为它是从头开始设计的,以支持静态验证。 + +您可以使用运行时地址值(地址类型的值)来访问该地址处的资源。您不能在运行时通过地址值访问模块。 + +## Addresses and Their Syntax + +Addresses come in two flavors, named or numerical. The syntax for a named address follows the +same rules for any named identifier in Move. The syntax of a numerical address is not restricted +to hex-encoded values, and any valid [`u128` numerical value](./integers.md) can be used as an +address value, e.g., `42`, `0xCAFE`, and `2021` are all valid numerical address +literals. + +To distinguish when an address is being used in an expression context or not, the +syntax when using an address differs depending on the context where it's used: +* When an address is used as an expression the address must be prefixed by the `@` character, i.e., `@`[``](./integers.md) or `@`. +* Outside of expression contexts, the address may be written without the leading `@` character, i.e., [``](./integers.md) or ``. + +In general, you can think of `@` as an operator that takes an address from being a namespace item to being an expression item. +## 地址及其语法 +地址有两种形式,命名的或数字的。命名地址的语法遵循 Move 中任何命名标识符的相同规则。数字地址的语法不限于十六进制编码值,任何有效的 u128 数字值都可以用作地址值,例如 42、0xCAFE 和 2021 都是有效的数字地址文字。 + +为了区分何时在表达式上下文中使用地址,使用地址时的语法根据使用地址的上下文而有所不同: + +当地址用作表达式时,地址必须以 @ 字符为前缀,即 @ numeric_value 或 @named_address_identifier 。 +在表达式上下文之外,地址可以不带前导 @ 字符,即 numeric_value 或 named_address_identifier 。 +通常,您可以将 @ 视为将地址从命名空间项变为表达式项的运算符。 + +## Named Addresses + +Named addresses are a feature that allow identifiers to be used in place of +numerical values in any spot where addresses are used, and not just at the +value level. Named addresses are declared and bound as top level elements +(outside of modules and scripts) in Move Packages, or passed as arguments +to the Move compiler. + +Named addresses only exist at the source language level and will be fully +substituted for their value at the bytecode level. Because of this, modules +and module members _must_ be accessed through the module's named address +and not through the numerical value assigned to the named address during +compilation, e.g., `use my_addr::foo` is _not_ equivalent to `use 0x2::foo` +even if the Move program is compiled with `my_addr` set to `0x2`. This +distinction is discussed in more detail in the section on [Modules and +Scripts](./modules-and-scripts.md). +## 命名地址 +命名地址是一项功能,它允许在使用地址的任何地方使用标识符代替数值,而不仅仅是在值级别。命名地址被声明并绑定为 Move 包中的顶级元素(模块和脚本之外),或作为参数传递给 Move 编译器。 + +命名地址仅存在于源语言级别,并将在字节码级别完全替代它们的值。因此,必须通过模块的命名地址访问模块和模块成员,而不是通过编译期间分配给命名地址的数值,例如,使用 my_addr::foo 不等同于使用 0x2::foo,即使 Move程序编译时将 my_addr 设置为 0x2。这种区别在模块和脚本一节中有更详细的讨论。 + +### Examples +### 例子 + +```move +let a1: address = @0x1; // shorthand for 0x00000000000000000000000000000001 +let a2: address = @0x42; // shorthand for 0x00000000000000000000000000000042 +let a3: address = @0xDEADBEEF; // shorthand for 0x000000000000000000000000DEADBEEF +let a4: address = @0x0000000000000000000000000000000A; +let a5: address = @std; // Assigns `a5` the value of the named address `std` +let a6: address = @66; +let a7: address = @0x42; + +module 66::some_module { // Not in expression context, so no @ needed + use 0x1::other_module; // Not in expression context so no @ needed + use std::vector; // Can use a named address as a namespace item when using other modules + ... +} + +module std::other_module { // Can use a named address as a namespace item to declare a module + ... +} +``` + +## Global Storage Operations + +The primary purpose of `address` values are to interact with the global storage operations. + +`address` values are used with the `exists`, `borrow_global`, `borrow_global_mut`, and `move_from` [operations](./global-storage-operators.md). + +The only global storage operation that *does not* use `address` is `move_to`, which uses [`signer`](./signer.md). +## 全局存储操作符 +地址值的主要目的是与全局存储操作进行交互。 + +地址值与exists、borrow_global、borrow_global_mut 和move_from 操作一起使用。 + +唯一不使用地址的全局存储操作是move_to,它使用了signer。 + +## Ownership + +As with the other scalar values built-in to the language, `address` values are implicitly copyable, meaning they can be copied without an explicit instruction such as [`copy`](./variables.md#move-and-copy). +## 所有权 +与语言中内置的其他标量值一样,地址值是隐式可复制的,这意味着它们可以在没有显式指令(例如复制)的情况下复制。 diff --git a/language/documentation/book/translations/move-book-zh/src/bool.md b/language/documentation/book/translations/move-book-zh/src/bool.md new file mode 100644 index 0000000000..42a19fbfbf --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/bool.md @@ -0,0 +1,44 @@ +# Bool + +`bool` is Move's primitive type for boolean `true` and `false` values. +# 布尔 +bool 是 Move 的布尔真假值的原始类型。 + +## Literals + +Literals for `bool` are either `true` or `false`. +## 字面量 +bool 的文字为真或假。 + +## Operations + +### Logical + +`bool` supports three logical operations: +## 操作符 +### 逻辑的 +bool 支持三种逻辑运算: + +| Syntax | Description | Equivalent Expression | +| ------------------------- | ---------------------------- | ------------------------------------------------------------------- | +| `&&` | short-circuiting logical and | `p && q` is equivalent to `if (p) q else false` | +| || | short-circuiting logical or | p || q is equivalent to `if (p) true else q` | +| `!` | logical negation | `!p` is equivalent to `if (p) false else true` | + +### Control Flow + +`bool` values are used in several of Move's control-flow constructs: +### 控制流 +布尔值用于 Move 的多个控制流结构中: + +- [`if (bool) { ... }`](./conditionals.md) +- [`while (bool) { .. }`](./loops.md) +- [`assert!(bool, u64)`](./abort-and-assert.md) + +## Ownership + +As with the other scalar values built-in to the language, boolean values are implicitly copyable, +meaning they can be copied without an explicit instruction such as +[`copy`](./variables.md#move-and-copy). +## 所有权 +与语言内置的其他标量值一样,布尔值是隐式可复制的,这意味着它们可以在没有显式指令(如复制)的情况下复制。 diff --git a/language/documentation/book/translations/move-book-zh/src/coding-conventions.md b/language/documentation/book/translations/move-book-zh/src/coding-conventions.md new file mode 100644 index 0000000000..5946764147 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/coding-conventions.md @@ -0,0 +1,114 @@ +# Move Coding Conventions + +This section lays out some basic coding conventions for Move that the Move team has found helpful. These are only recommendations, and you should feel free to use other formatting guidelines and conventions if you have a preference for them. + +# 移动编码约定 +本部分列出了 Move 团队认为有用的一些基本编码约定。这些只是建议,如果您有偏好,可以随意使用其他格式指南和约定。 + +## Naming + +- **Module names**: should be lower snake case, e.g., `fixed_point32`, `vector` +- **Type names**: should be camel case if they are not a native type, e.g., `Coin`, `RoleId` +- **Function names**: should be lower snake case, e.g., `destroy_empty` +- **Constant names**: should be upper snake case, e.g., `REQUIRES_CAPABILITY` +- Generic types should be descriptive, or anti-descriptive where appropriate, e.g., `T` or `Element` for the Vector generic type parameter. Most of the time the "main" type in a module should be the same name as the module e.g., `option::Option`, `fixed_point32::FixedPoint32`. +- **Module file names**: should be the same as the module name e.g., `Option.move` +- **Script file names**: should be lower snake case and should match the name of the “main” function in the script. +- **Mixed file names**: If the file contains multiple modules and/or scripts, the file name should be lower_snake_case, where the name does not match any particular module/script inside. + +## 命名 + +- 模块名称:应该是小写蛇形,例如,fixed_point32、vector +- 类型名称:如果它们不是本地类型,则应为驼峰式,例如 Coin、RoleId +- 函数名:应该是小写的蛇形,例如,destroy_empty +- 常量名称:应该是大写的蛇形,例如,REQUIRES_CAPABILITY +- 泛型类型应该是描述性的,或者在适当的情况下是反描述性的,例如 Vector 泛型类型参数的 T 或 Element。大多数情况下,模块中的“主”类型应该与模块名称相同,例如 option::Option、fixed_point32::FixedPoint32。 +- 模块文件名:应与模块名称相同,例如 Option.move +- 脚本文件名:应该是小写的蛇,并且应该与脚本中“main”函数的名称相匹配。 +- 混合文件名:如果文件包含多个模块和/或脚本,则文件名应为 lower_snake_case,其中名称与内部的任何特定模块/脚本不匹配。 + +## Imports + +- All module `use` statements should be at the top of the module. +- Functions should be imported and used fully qualified from the module in which they are declared, and not imported at the top level. +- Types should be imported at the top-level. Where there are name clashes, `as` should be used to rename the type locally as appropriate. + +For example, if there is a module + +## 导入 + +所有模块使用语句都应该在模块的顶部。 +函数应该从声明它们的模块完全限定地导入和使用,而不是在顶层导入。 +类型应该在顶层导入。在存在名称冲突的情况下,应该使用 as 在本地适当地重命名类型。 +例如,如果有一个模块 + +```move= +module 0x1::foo { + struct Foo { } + const CONST_FOO: u64 = 0; + public fun do_foo(): Foo { Foo{} } + ... +} +``` + +this would be imported and used as: + +这将被导入并用作: + +```move= +module 0x1::bar { + use 0x1::foo::{Self, Foo}; + + public fun do_bar(x: u64): Foo { + if (x == 10) { + foo::do_foo() + } else { + abort 0 + } + } + ... +} +``` + +And, if there is a local name-clash when importing two modules: + +并且,如果在导入两个模块时存在本地名称冲突: + +```move= +module other_foo { + struct Foo {} + ... +} + +module 0x1::importer { + use 0x1::other_foo::Foo as OtherFoo; + use 0x1::foo::Foo; +.... +} +``` + +## Comments + +- Each module, struct, and public function declaration should be commented +- Move has doc comments `///`, regular single-line comments `//`, block comments `/* */`, and block doc comments `/** */` + +## 注释 + +- 应注释每个模块、结构和公共函数声明 +- Move 具有文档注释 `///`、常规单行注释 `//`、块注释 `/* */` 和块文档注释 `/** */` + +## Formatting + +The Move team plans to write an autoformatter to enforce formatting conventions. However, in the meantime: + +- Four space indentation should be used except for `script` and `address` blocks whose contents should not be indented +- Lines should be broken if they are longer than 100 characters +- Structs and constants should be declared before all functions in a module + +## 格式化 + +Move 团队计划编写一个自动格式化程序来强制执行格式化约定。然而,与此同时: + +- 除了内容不应缩进的脚本和地址块外,应使用四个空格缩进 +- 超过 100 个字符的行应换行 +- 结构和常量应该在模块中的所有函数之前声明 diff --git a/language/documentation/book/translations/move-book-zh/src/conditionals.md b/language/documentation/book/translations/move-book-zh/src/conditionals.md new file mode 100644 index 0000000000..795b95fc6c --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/conditionals.md @@ -0,0 +1,79 @@ +# Conditionals + +An `if` expression specifies that some code should only be evaluated if a certain condition is true. For example: +# 条件句 +if 表达式指定仅当某个条件为真时才应评估某些代码。例如: + +```move +if (x > 5) x = x - 5 +``` + +The condition must be an expression of type `bool`. + +An `if` expression can optionally include an `else` clause to specify another expression to evaluate when the condition is false. + +条件必须是布尔类型的表达式。 + +if 表达式可以选择包含 else 子句,以指定另一个表达式在条件为假时进行评估。 + +```move +if (y <= 10) y = y + 1 else y = 10 +``` + +Either the "true" branch or the "false" branch will be evaluated, but not both. Either branch can be a single expression or an expression block. + +The conditional expressions may produce values so that the `if` expression has a result. +将评估“真”分支或“假”分支,但不会同时评估两者。任何一个分支都可以是单个表达式或表达式块。 + +条件表达式可以产生值,以便 if 表达式有结果。 + +```move +let z = if (x < 100) x else 100; +``` + +The expressions in the true and false branches must have compatible types. For example: + +true 和 false 分支中的表达式必须具有兼容的类型。例如: + +```move= +// x and y must be u64 integers +let maximum: u64 = if (x > y) x else y; + +// ERROR! branches different types +let z = if (maximum < 10) 10u8 else 100u64; + +// ERROR! branches different types, as default false-branch is () not u64 +if (maximum >= 10) maximum; +``` + +If the `else` clause is not specified, the false branch defaults to the unit value. The following are equivalent: + +如果没有指定 else 子句,则 false 分支默认为单位值。以下是等价的: + +```move +if (condition) true_branch // implied default: else () +if (condition) true_branch else () +``` + +Commonly, [`if` expressions](./conditionals.md) are used in conjunction with expression blocks. + +通常,if 表达式与表达式块一起使用。 + +```move +let maximum = if (x > y) x else y; +if (maximum < 10) { + x = x + 10; + y = y + 10; +} else if (x >= 10 && y >= 10) { + x = x - 10; + y = y - 10; +} +``` + +## Grammar for Conditionals + +> *if-expression* → **if (** *expression* **)** *expression* *else-clause**opt* +> *else-clause* → **else** *expression* + +## 条件语法 +if 表达式 → if ( 表达式 ) 表达式 else-clauseopt else-clause → else 表达式 diff --git a/language/documentation/book/translations/move-book-zh/src/constants.md b/language/documentation/book/translations/move-book-zh/src/constants.md new file mode 100644 index 0000000000..69a3c13eeb --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/constants.md @@ -0,0 +1,140 @@ +# Constants + +Constants are a way of giving a name to shared, static values inside of a `module` or `script`. + +The constant's must be known at compilation. The constant's value is stored in the compiled module +or script. And each time the constant is used, a new copy of that value is made. +# 常数 +常量是为模块或脚本内的共享静态值命名的一种方式。 + +常量必须在编译时知道。常量的值存储在编译的模块或脚本中。每次使用该常量时,都会生成该值的新副本。 + +## Declaration + +Constant declarations begin with the `const` keyword, followed by a name, a type, and a value. They +can exist in either a script or module +## 声明 + +常量声明以 const 关键字开头,后跟名称、类型和值。它们可以存在于脚本或模块中 + +```text +const : = ; +``` + +For example + +例如 + +```move= +script { + + const MY_ERROR_CODE: u64 = 0; + + fun main(input: u64) { + assert!(input > 0, MY_ERROR_CODE); + } + +} + +address 0x42 { +module example { + + const MY_ADDRESS: address = @0x42; + + public fun permissioned(s: &signer) { + assert!(std::signer::address_of(s) == MY_ADDRESS, 0); + } + +} +} +``` + +## Naming + +Constants must start with a capital letter `A` to `Z`. After the first letter, constant names can +contain underscores `_`, letters `a` to `z`, letters `A` to `Z`, or digits `0` to `9`. +## 命名 +常量必须以大写字母 A 到 Z 开头。在第一个字母之后,常量名称可以包含下划线 `_`、字母 a 到 z、字母 A 到 Z 或数字 0 到 9。 + +```move +const FLAG: bool = false; +const MY_ERROR_CODE: u64 = 0; +const ADDRESS_42: address = @0x42; +``` + +Even though you can use letters `a` to `z` in a constant. The +[general style guidelines](./coding-conventions.md) are to use just uppercase letters `A` to `Z`, +with underscores `_` between each word. + +This naming restriction of starting with `A` to `Z` is in place to give room for future language +features. It may or may not be removed later. + +即使您可以在常数中使用字母 a 到 z。一般的风格准则是只使用大写字母 A 到 Z,每个单词之间用下划线 `_`。 + +这种以 A 到 Z 开头的命名限制是为了给未来的语言特性留出空间。以后可能会或可能不会删除它。 + +## Visibility + +`public` constants are not currently supported. `const` values can be used only in the declaring +module. +## 可见性 +当前不支持公共常量。 const 值只能在声明模块中使用。 + +## Valid Expressions + +Currently, constants are limited to the primitive types `bool`, `u8`, `u64`, `u128`, `address`, and +`vector`. Future support for other `vector` values (besides the "string"-style literals) will +come later. +## 有效表达式 +目前,常量仅限于基本类型 bool、u8、u64、u128、address 和向量 u8。未来对其他向量值的支持(除了“字符串”样式的文字)将在稍后提供。 + +### Values + +Commonly, `const`s are assigned a simple value, or literal, of their type. For example +### 值 + +通常,为 const 分配其类型的简单值或文字。例如 + +```move +const MY_BOOL: bool = false; +const MY_ADDRESS: address = @0x70DD; +const BYTES: vector = b"hello world"; +const HEX_BYTES: vector = x"DEADBEEF"; +``` + +### Complex Expressions + +In addition to literals, constants can include more complex expressions, as long as the compiler is +able to reduce the expression to a value at compile time. + +Currently, equality operations, all boolean operations, all bitwise operations, and all arithmetic +operations can be used. +### 复杂表达式 +除了文字之外,常量还可以包含更复杂的表达式,只要编译器能够在编译时将表达式简化为一个值即可。 + +目前,可以使用相等运算、所有布尔运算、所有位运算和所有算术运算。 + +```move +const RULE: bool = true && false; +const CAP: u64 = 10 * 100 + 1; +const SHIFTY: u8 = { + (1 << 1) * (1 << 2) * (1 << 3) * (1 << 4) +}; +const HALF_MAX: u128 = 340282366920938463463374607431768211455 / 2; +const EQUAL: bool = 1 == 1; +``` + +If the operation would result in a runtime exception, the compiler will give an error that it is +unable to generate the constant's value + +如果操作会导致运行时异常,编译器将给出无法生成常量值的错误 + +```move +const DIV_BY_ZERO: u64 = 1 / 0; // error! +const SHIFT_BY_A_LOT: u64 = 1 << 100; // error! +const NEGATIVE_U64: u64 = 0 - 1; // error! +``` + +Note that constants cannot currently refer to other constants. This feature, along with support for +other expressions, will be added in the future. +请注意,常量当前不能引用其他常量。将来会添加此功能以及对其他表达式的支持。 diff --git a/language/documentation/book/translations/move-book-zh/src/creating-coins.md b/language/documentation/book/translations/move-book-zh/src/creating-coins.md new file mode 100644 index 0000000000..2fe52bad85 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/creating-coins.md @@ -0,0 +1,5 @@ +# Move Tutorial + +Please refer to the [Move Tutorial](https://github.com/move-language/move/tree/main/language/documentation/tutorial). +# 移动教程 +请参阅移动教程。 diff --git a/language/documentation/book/translations/move-book-zh/src/equality.md b/language/documentation/book/translations/move-book-zh/src/equality.md new file mode 100644 index 0000000000..3f20f35a02 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/equality.md @@ -0,0 +1,190 @@ +# Equality + +Move supports two equality operations `==` and `!=` +# 平等 +Move 支持两个相等操作 == 和 != + +## Operations +## 操作符 + +| Syntax | Operation | Description | +| ------ | --------- | --------------------------------------------------------------------------- | +| `==` | equal | Returns `true` if the two operands have the same value, `false` otherwise | +| `!=` | not equal | Returns `true` if the two operands have different values, `false` otherwise | + +### Typing + +Both the equal (`==`) and not-equal (`!=`) operations only work if both operands are the same type +### 打字 +相等 (==) 和不相等 (!=) 操作仅在两个操作数为相同类型时才有效 + +```move +0 == 0; // `true` +1u128 == 2u128; // `false` +b"hello" != x"00"; // `true` +``` + +Equality and non-equality also work over user defined types! + +相等和不相等也适用于用户定义的类型! + +```move= +address 0x42 { +module example { + struct S has copy, drop { f: u64, s: vector } + + fun always_true(): bool { + let s = S { f: 0, s: b"" }; + // parens are not needed but added for clarity in this example + (copy s) == s + } + + fun always_false(): bool { + let s = S { f: 0, s: b"" }; + // parens are not needed but added for clarity in this example + (copy s) != s + } +} +} +``` + +If the operands have different types, there is a type checking error + +如果操作数具有不同的类型,则存在类型检查错误 + +```move +1u8 == 1u128; // ERROR! +// ^^^^^ expected an argument of type 'u8' +b"" != 0; // ERROR! +// ^ expected an argument of type 'vector' +``` + +### Typing with references + +When comparing [references](./references.md), the type of the reference (immutable or mutable) does +not matter. This means that you can compare an immutable `&` reference with a mutable one `&mut` of +the same underlying type. +### 使用参考打字 +比较引用时,引用的类型(不可变或可变)无关紧要。这意味着您可以将不可变的 & 引用与相同基础类型的可变 &mut 进行比较。 + +```move +let i = &0; +let m = &mut 1; + +i == m; // `false` +m == i; // `false` +m == m; // `true` +i == i; // `true` +``` + +The above is equivalent to applying an explicit freeze to each mutable reference where needed + +以上相当于在需要时对每个可变引用应用显式冻结 + +```move +let i = &0; +let m = &mut 1; + +i == freeze(m); // `false` +freeze(m) == i; // `false` +m == m; // `true` +i == i; // `true` +``` + +But again, the underlying type must be the same type + +但同样,基础类型必须是相同的类型 + +```move +let i = &0; +let s = &b""; + +i == s; // ERROR! +// ^ expected an argument of type '&u64' +``` + +## Restrictions + +Both `==` and `!=` consume the value when comparing them. As a result, the type system enforces that +the type must have [`drop`](./abilities.md). Recall that without the +[`drop` ability](./abilities.md), ownership must be transferred by the end of the function, and such +values can only be explicitly destroyed within their declaring module. If these were used directly +with either equality `==` or non-equality `!=`, the value would be destroyed which would break +[`drop` ability](./abilities.md) safety guarantees! + +## 限制 +== 和 != 在比较它们时都会消耗值。结果,类型系统强制该类型必须具有 drop。回想一下,如果没有 drop 能力,所有权必须在函数结束时转移,并且这些值只能在其声明模块中显式销毁。如果这些直接与相等 == 或不相等 != 一起使用,则该值将被破坏,这将破坏掉落能力的安全保证! + +```move= +address 0x42 { +module example { + struct Coin has store { value: u64 } + fun invalid(c1: Coin, c2: Coin) { + c1 == c2 // ERROR! +// ^^ ^^ These resources would be destroyed! + } +} +} +``` + +But, a programmer can _always_ borrow the value first instead of directly comparing the value, and +reference types have the [`drop` ability](./abilities.md). For example + +但是,程序员总是可以先借值而不是直接比较值,并且引用类型具有删除能力。例如 + +```move= +address 0x42 { +module example { + struct Coin as store { value: u64 } + fun swap_if_equal(c1: Coin, c2: Coin): (Coin, Coin) { + let are_equal = &c1 == &c2; // valid + if (are_equal) (c2, c1) else (c1, c2) + } +} +} +``` + +## Avoid Extra Copies + +While a programmer _can_ compare any value whose type has [`drop`](./abilities.md), a programmer +should often compare by reference to avoid expensive copies. +## 避免额外的副本 +虽然程序员可以比较任何类型下降的值,但程序员应该经常通过引用进行比较以避免昂贵的副本。 + +```move= +let v1: vector = function_that_returns_vector(); +let v2: vector = function_that_returns_vector(); +assert!(copy v1 == copy v2, 42); +// ^^^^ ^^^^ +use_two_vectors(v1, v2); + +let s1: Foo = function_that_returns_large_struct(); +let s2: Foo = function_that_returns_large_struct(); +assert!(copy s1 == copy s2, 42); +// ^^^^ ^^^^ +use_two_foos(s1, s2); +``` + +This code is perfectly acceptable (assuming `Foo` has [`drop`](./abilities.md)), just not efficient. +The highlighted copies can be removed and replaced with borrows + +这段代码是完全可以接受的(假设 Foo 已经下降),只是效率不高。突出显示的副本可以删除并替换为借用 + +```move= +let v1: vector = function_that_returns_vector(); +let v2: vector = function_that_returns_vector(); +assert!(&v1 == &v2, 42); +// ^ ^ +use_two_vectors(v1, v2); + +let s1: Foo = function_that_returns_large_struct(); +let s2: Foo = function_that_returns_large_struct(); +assert!(&s1 == &s2, 42); +// ^ ^ +use_two_foos(s1, s2); +``` + +The efficiency of the `==` itself remains the same, but the `copy`s are removed and thus the program +is more efficient. + +== 本身的效率保持不变,但副本被删除,因此程序效率更高。 diff --git a/language/documentation/book/translations/move-book-zh/src/friends.md b/language/documentation/book/translations/move-book-zh/src/friends.md new file mode 100644 index 0000000000..dbd7276fc0 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/friends.md @@ -0,0 +1,162 @@ +# Friends + +The `friend` syntax is used to declare modules that are trusted by the current module. +A trusted module is allowed to call any function defined in the current module that have the `public(friend)` visibility. +For details on function visibilities, please refer to the *Visibility* section in [Functions](./functions.md). + +# 友元 + +友元语法用于声明当前模块信任的模块。允许受信任的模块调用当前模块中定义的任何具有公共(朋友)可见性的函数。有关函数可见性的详细信息,请参阅函数中的可见性部分。 + +## Friend declaration + +A module can declare other modules as friends via friend declaration statements, in the format of + +- `friend ` — friend declaration using fully qualified module name like the example below, or +## 友元声明 +一个模块可以通过友元声明语句将其他模块声明为友元,格式为 + +- `friend ` — 使用完全限定模块名称的朋友声明,如下例所示,或 + + ```move + address 0x42 { + module a { + friend 0x42::b; + } + } + ``` + +- `friend ` — friend declaration using a module name alias, where the module alias is introduced via the `use` statement. + +- `friend `——使用模块名称别名的朋友声明,其中模块别名是通过 use 语句引入的。 + + ```move + address 0x42 { + module a { + use 0x42::b; + friend b; + } + } + ``` + +A module may have multiple friend declarations, and the union of all the friend modules forms the friend list. +In the example below, both `0x42::B` and `0x42::C` are considered as friends of `0x42::A`. + +一个模块可能有多个好友声明,所有好友模块的并集形成好友列表。在下面的示例中,0x42::B 和 0x42::C 都被视为 0x42::A 的朋友。 + +```move +address 0x42 { +module a { + friend 0x42::b; + friend 0x42::c; +} +} +``` + +Unlike `use` statements, `friend` can only be declared in the module scope and not in the expression block scope. +`friend` declarations may be located anywhere a top-level construct (e.g., `use`, `function`, `struct`, etc.) is allowed. +However, for readability, it is advised to place friend declarations near the beginning of the module definition. + +Note that the concept of friendship does not apply to Move scripts: +- A Move script cannot declare `friend` modules as doing so is considered meaningless: there is no mechanism to call the function defined in a script. +- A Move module cannot declare `friend` scripts as well because scripts are ephemeral code snippets that are never published to global storage. + +与 use 语句不同,friend 只能在模块范围内声明,而不能在表达式块范围内声明。友元声明可以位于允许顶级构造(例如,使用、函数、结构等)的任何地方。但是,为了可读性,建议将友元声明放在模块定义的开头附近。 + +请注意,友谊的概念不适用于 Move 脚本: + +- Move 脚本不能声明友元模块,因为这样做被认为是没有意义的:没有调用脚本中定义的函数的机制。 +- Move 模块也不能声明友元脚本,因为脚本是临时代码片段,从未发布到全局存储。 + +### Friend declaration rules +Friend declarations are subject to the following rules: + +- A module cannot declare itself as a friend. + +### 好友声明规则 +朋友声明须遵守以下规则: + +- 模块不能将自己声明为友元。 + + ```move= + address 0x42 { + module m { friend Self; // ERROR! } + // ^^^^ Cannot declare the module itself as a friend + } + + address 0x43 { + module m { friend 0x43::M; // ERROR! } + // ^^^^^^^ Cannot declare the module itself as a friend + } + ``` + +- Friend modules must be known by the compiler +- 编译器必须知道友元模块 + + ```move= + address 0x42 { + module m { friend 0x42::nonexistent; // ERROR! } + // ^^^^^^^^^^^^^^^^^ Unbound module '0x42::nonexistent' + } + ``` + +- Friend modules must be within the same account address. (Note: this is not a technical requirement but rather a policy decision which *may* be relaxed later.) +- 好友模块必须在同一个账户地址内。 (注:这不是技术要求,而是以后可能放宽的政策决定。) + + ```move= + address 0x42 { + module m {} + } + + address 0x43 { + module n { friend 0x42::m; // ERROR! } + // ^^^^^^^ Cannot declare modules out of the current address as a friend + } + ``` + +- Friends relationships cannot create cyclic module dependencies. + + Cycles are not allowed in the friend relationships, e.g., the relation `0x2::a` friends `0x2::b` friends `0x2::c` friends `0x2::a` is not allowed. +More generally, declaring a friend module adds a dependency upon the current module to the friend module (because the purpose is for the friend to call functions in the current module). +If that friend module is already used, either directly or transitively, a cycle of dependencies would be created. +- 朋友关系不能创建循环模块依赖关系。 + +朋友关系中不允许循环,例如,关系 0x2::a 朋友 0x2::b 朋友 0x2::c 朋友 0x2::a 是不允许的。更一般地,声明一个友元模块会将对当前模块的依赖添加到友元模块(因为目的是让友元调用当前模块中的函数)。如果该友元模块已被直接或传递地使用,则将创建一个依赖循环。 + + ```move= + address 0x2 { + module a { + use 0x2::c; + friend 0x2::b; + + public fun a() { + c::c() + } + } + + module b { + friend 0x2::c; // ERROR! + // ^^^^^^ This friend relationship creates a dependency cycle: '0x2::b' is a friend of '0x2::a' uses '0x2::c' is a friend of '0x2::b' + } + + module c { + public fun c() {} + } + } + ``` + +- The friend list for a module cannot contain duplicates. +- 模块的好友列表不能包含重复项。 + + ```move= + address 0x42 { + module a {} + + module m { + use 0x42::a as aliased_a; + friend 0x42::A; + friend aliased_a; // ERROR! + // ^^^^^^^^^ Duplicate friend declaration '0x42::a'. Friend declarations in a module must be unique + } + } + ``` diff --git a/language/documentation/book/translations/move-book-zh/src/functions.md b/language/documentation/book/translations/move-book-zh/src/functions.md new file mode 100644 index 0000000000..271c8b976d --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/functions.md @@ -0,0 +1,616 @@ +# Functions + +Function syntax in Move is shared between module functions and script functions. Functions inside of modules are reusable, whereas script functions are only used once to invoke a transaction. +# 函数 +Move 中的函数语法在模块函数和脚本函数之间共享。模块内部的函数是可重用的,而脚本函数仅用于调用事务一次。 + +## Declaration + +Functions are declared with the `fun` keyword followed by the function name, type parameters, parameters, a return type, acquires annotations, and finally the function body. + +## 声明 +函数用 fun 关键字声明,后跟函数名、类型参数、形参、返回类型、获取注解,最后是函数体。 + +```text +fun <[type_parameters: constraint],*>([identifier: type],*): +``` + +For example + +例如 + +```move +fun foo(x: u64, y: T1, z: T2): (T2, T1, u64) { (z, y, x) } +``` + +### Visibility + +Module functions, by default, can only be called within the same module. These internal (sometimes called private) functions cannot be called from other modules or from scripts. + +### 可见性 +默认情况下,模块函数只能在同一个模块内调用。这些内部(有时称为私有)函数不能从其他模块或脚本调用。 + +```move= +address 0x42 { +module m { + fun foo(): u64 { 0 } + fun calls_foo(): u64 { foo() } // valid +} + +module other { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' is internal to '0x42::m' + } +} +} + +script { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' is internal to '0x42::m' + } +} +``` + +To allow access from other modules or from scripts, the function must be declared `public` or `public(friend)`. +要允许从其他模块或脚本访问,该函数必须声明为 public 或 public(friend)。 + +#### `public` visibility + +A `public` function can be called by *any* function defined in *any* module or script. As shown in the following example, a `public` function can be called by: +- other functions defined in the same module, +- functions defined in another module, or +- the function defined in a script. + +#### `public` 可见性 +公共函数可以被任何模块或脚本中定义的任何函数调用。如以下示例所示,可以通过以下方式调用公共函数: + +在同一模块中定义的其他功能, +在另一个模块中定义的函数,或 +脚本中定义的函数。 + +```move= +address 0x42 { +module m { + public fun foo(): u64 { 0 } + fun calls_foo(): u64 { foo() } // valid +} + +module other { + fun calls_m_foo(): u64 { + 0x42::m::foo() // valid + } +} +} + +script { + fun calls_m_foo(): u64 { + 0x42::m::foo() // valid + } +} +``` + +#### `public(friend)` visibility + +The `public(friend)` visibility modifier is a more restricted form of the `public` modifier to give more control about where a function can be used. A `public(friend)` function can be called by: +- other functions defined in the same module, or +- functions defined in modules which are explicitly specified in the **friend list** (see [Friends](./friends.md) on how to specify the friend list). + +Note that since we cannot declare a script to be a friend of a module, the functions defined in scripts can never call a `public(friend)` function. +#### `public(friend)` 可见性 +public(friend) 可见性修饰符是 public 修饰符的一种更受限制的形式,可以更好地控制函数的使用位置。可以通过以下方式调用公共(朋友)函数: + +在同一模块中定义的其他功能,或 +在好友列表中明确指定的模块中定义的函数(请参阅好友了解如何指定好友列表)。 +请注意,由于我们不能将脚本声明为模块的朋友,因此脚本中定义的函数永远不能调用 public(friend) 函数。 + +```move= +address 0x42 { +module m { + friend 0x42::n; // friend declaration + public(friend) fun foo(): u64 { 0 } + fun calls_foo(): u64 { foo() } // valid +} + +module n { + fun calls_m_foo(): u64 { + 0x42::m::foo() // valid + } +} + +module other { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' can only be called from a 'friend' of module '0x42::m' + } +} +} + +script { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' can only be called from a 'friend' of module '0x42::m' + } +} +``` + +### `entry` modifier + +The `entry` modifier is designed to allow module functions to be safely and directly invoked much like scripts. This allows module writers to specify which functions can be to begin execution. The module writer then knows that any non-`entry` function will be called from a Move program already in execution. + +Essentially, `entry` functions are the "main" functions of a module, and they specify where Move programs start executing. + +Note though, an `entry` function _can_ still be called by other Move functions. So while they _can_ serve as the start of a Move program, they aren't restricted to that case. + +For example: +### `entry` 修饰符 +entry 修饰符旨在允许像脚本一样安全直接地调用模块函数。这允许模块编写者指定哪些函数可以开始执行。然后,模块编写者知道任何非入口函数都将从已经在执行的 Move 程序中调用。 + +本质上,入口函数是模块的“主要”函数,它们指定 Move 程序开始执行的位置。 + +但请注意,其他 Move 函数仍然可以调用入口函数。因此,虽然它们可以作为 Move 程序的开始,但它们并不局限于这种情况。 + +例如: + +```move= +address 0x42 { +module m { + public entry fun foo(): u64 { 0 } + fun calls_foo(): u64 { foo() } // valid! +} + +module n { + fun calls_m_foo(): u64 { + 0x42::m::foo() // valid! + } +} + +module other { + public entry fun calls_m_foo(): u64 { + 0x42::m::foo() // valid! + } +} +} + +script { + fun calls_m_foo(): u64 { + 0x42::m::foo() // valid! + } +} +``` + +Even internal functions can be marked as `entry`! This lets you guarantee that the function is called only at the beginning of execution (assuming you do not call it elsewhere in your module) +甚至内部函数也可以标记为入口!这使您可以保证仅在执行开始时调用该函数(假设您没有在模块的其他地方调用它) + +```move= +address 0x42 { +module m { + entry fun foo(): u64 { 0 } // valid! entry functions do not have to be public +} + +module n { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' is internal to '0x42::m' + } +} + +module other { + public entry fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' is internal to '0x42::m' + } +} +} + +script { + fun calls_m_foo(): u64 { + 0x42::m::foo() // ERROR! +// ^^^^^^^^^^^^ 'foo' is internal to '0x42::m' + } +} +``` + +### Name + +Function names can start with letters `a` to `z` or letters `A` to `Z`. After the first character, function names can contain underscores `_`, letters `a` to `z`, letters `A` to `Z`, or digits `0` to `9`. +### 名称 +函数名称可以以字母 a 到 z 或字母 A 到 Z 开头。在第一个字符之后,函数名称可以包含下划线 `_`、字母 a 到 z、字母 A 到 Z 或数字 0 到 9。 + +```move +fun FOO() {} +fun bar_42() {} +fun _bAZ19() {} +``` + +### Type Parameters + +After the name, functions can have type parameters +### 类型参数 +在名称之后,函数可以有类型参数 + +```move +fun id(x: T): T { x } +fun example(x: T1, y: T2): (T1, T1, T2) { (copy x, x, y) } +``` + +For more details, see [Move generics](./generics.md). + +有关更多详细信息,请参阅移动泛型。 + +### Parameters + +Functions parameters are declared with a local variable name followed by a type annotation +### 参数 +函数参数使用局部变量名声明,后跟类型注释 + +```move +fun add(x: u64, y: u64): u64 { x + y } +``` + +We read this as `x` has type `u64` + +A function does not have to have any parameters at all. + +我们将其读为 x 具有 u64 类型 + +函数根本不需要任何参数。 + +```move +fun useless() { } +``` + +This is very common for functions that create new or empty data structures + +这对于创建新数据结构或空数据结构的函数很常见 + +```move= +address 0x42 { +module example { + struct Counter { count: u64 } + + fun new_counter(): Counter { + Counter { count: 0 } + } + +} +} +``` + +### Acquires + +When a function accesses a resource using `move_from`, `borrow_global`, or `borrow_global_mut`, the function must indicate that it `acquires` that resource. This is then used by Move's type system to ensure the references into global storage are safe, specifically that there are no dangling references into global storage. +### 收购 +当函数使用 move_from、borrow_global 或 borrow_global_mut 访问资源时,该函数必须表明它获取了该资源。然后 Move 的类型系统使用它来确保对全局存储的引用是安全的,特别是没有对全局存储的悬空引用。 + +```move= +address 0x42 { +module example { + + struct Balance has key { value: u64 } + + public fun add_balance(s: &signer, value: u64) { + move_to(s, Balance { value }) + } + + public fun extract_balance(addr: address): u64 acquires Balance { + let Balance { value } = move_from(addr); // acquires needed + value + } +} +} +``` + +`acquires` annotations must also be added for transitive calls within the module. Calls to these functions from another module do not need to annotated with these acquires because one module cannot access resources declared in another module--so the annotation is not needed to ensure reference safety. + +还必须为模块内的传递调用添加获取注释。从另一个模块对这些函数的调用不需要使用这些获取进行注释,因为一个模块无法访问在另一个模块中声明的资源——因此不需要注释来确保引用安全。 + +```move= +address 0x42 { +module example { + + struct Balance has key { value: u64 } + + public fun add_balance(s: &signer, value: u64) { + move_to(s, Balance { value }) + } + + public fun extract_balance(addr: address): u64 acquires Balance { + let Balance { value } = move_from(addr); // acquires needed + value + } + + public fun extract_and_add(sender: address, receiver: &signer) acquires Balance { + let value = extract_balance(sender); // acquires needed here + add_balance(receiver, value) + } +} +} + +address 0x42 { +module other { + fun extract_balance(addr: address): u64 { + 0x42::example::extract_balance(addr) // no acquires needed + } +} +} +``` + +A function can `acquire` as many resources as it needs to + +一个函数可以根据需要获取尽可能多的资源 + +```move= +address 0x42 { +module example { + use std::vector; + + struct Balance has key { value: u64 } + struct Box has key { items: vector } + + public fun store_two( + addr: address, + item1: Item1, + item2: Item2, + ) acquires Balance, Box { + let balance = borrow_global_mut(addr); // acquires needed + balance.value = balance.value - 2; + let box1 = borrow_global_mut>(addr); // acquires needed + vector::push_back(&mut box1.items, item1); + let box2 = borrow_global_mut>(addr); // acquires needed + vector::push_back(&mut box2.items, item2); + } +} +} +``` + +### Return type + +After the parameters, a function specifies its return type. +### 返回类型 +在参数之后,函数指定其返回类型。 + +```move +fun zero(): u64 { 0 } +``` + +Here `: u64` indicates that the function's return type is `u64`. + +Using tuples, a function can return multiple values + +这里:u64 表示函数的返回类型是u64。 + +使用元组,一个函数可以返回多个值 + +```move +fun one_two_three(): (u64, u64, u64) { (0, 1, 2) } +``` + +If no return type is specified, the function has an implicit return type of unit `()`. These functions are equivalent + +如果未指定返回类型,则该函数具有隐式返回类型 unit ()。这些功能是等价的 + +```move +fun just_unit(): () { () } +fun just_unit() { () } +fun just_unit() { } +``` + +`script` functions must have a return type of unit `()` + +脚本函数的返回类型必须为 unit () + +```move= +script { + fun do_nothing() { + } +} +``` + +As mentioned in the [tuples section](./tuples.md), these tuple "values" are virtual and do not exist at runtime. So for a function that returns unit `()`, it will not be returning any value at all during execution. + +如元组部分所述,这些元组“值”是虚拟的,在运行时不存在。因此,对于返回 unit () 的函数,它在执行期间根本不会返回任何值。 + +### Function body + +A function's body is an expression block. The return value of the function is the last value in the sequence + +### 函数体 +函数体是一个表达式块。函数的返回值是序列中的最后一个值 + +```move= +fun example(): u64 { + let x = 0; + x = x + 1; + x // returns 'x' +} +``` + +See [the section below for more information on returns](#returning-values) + +For more information on expression blocks, see [Move variables](./variables.md). + +有关退货的更多信息,请参阅以下部分 + +有关表达式块的更多信息,请参阅移动变量。 + +### Native Functions + +Some functions do not have a body specified, and instead have the body provided by the VM. These functions are marked `native`. + +Without modifying the VM source code, a programmer cannot add new native functions. Furthermore, it is the intent that `native` functions are used for either standard library code or for functionality needed for the given Move environment. + +Most `native` functions you will likely see are in standard library code such as `vector` +### 原生函数 +有些函数没有指定主体,而是由 VM 提供的主体。这些函数被标记为原生。 + +如果不修改 VM 源代码,程序员就无法添加新的本地函数。此外,本机函数的意图是用于标准库代码或给定 Move 环境所需的功能。 + +您可能会看到的大多数本机函数都在标准库代码中,例如向量 + +```move= +module std::vector { + native public fun empty(): vector; + ... +} +``` + +## Calling + +When calling a function, the name can be specified either through an alias or fully qualified + +## 调用 +调用函数时,名称可以通过别名或完全限定指定 + +```move= +address 0x42 { +module example { + public fun zero(): u64 { 0 } +} +} + +script { + use 0x42::example::{Self, zero}; + fun call_zero() { + // With the `use` above all of these calls are equivalent + 0x42::example::zero(); + example::zero(); + zero(); + } +} +``` + +When calling a function, an argument must be given for every parameter. + +调用函数时,必须为每个参数指定一个参数。 + +```move= +address 0x42 { +module example { + public fun takes_none(): u64 { 0 } + public fun takes_one(x: u64): u64 { x } + public fun takes_two(x: u64, y: u64): u64 { x + y } + public fun takes_three(x: u64, y: u64, z: u64): u64 { x + y + z } +} +} + +script { + use 0x42::example; + fun call_all() { + example::takes_none(); + example::takes_one(0); + example::takes_two(0, 1); + example::takes_three(0, 1, 2); + } +} +``` + +Type arguments can be either specified or inferred. Both calls are equivalent. + +可以指定或推断类型参数。两个调用是等价的。 + +```move= +address 0x42 { +module example { + public fun id(x: T): T { x } +} +} + +script { + use 0x42::example; + fun call_all() { + example::id(0); + example::id(0); + } +} +``` + +For more details, see [Move generics](./generics.md). + +有关更多详细信息,请参阅移动泛型。 + +## Returning values + +The result of a function, its "return value", is the final value of its function body. For example + +## 返回值 +一个函数的结果,它的“返回值”,是它的函数体的最终值。例如 + +```move= +fun add(x: u64, y: u64): u64 { + x + y +} +``` + +[As mentioned above](#function-body), the function's body is an [expression block](./variables.md). The expression block can sequence various statements, and the final expression in the block will be be the value of that block + +如上所述,函数体是一个表达式块。表达式块可以对各种语句进行排序,块中的最终表达式将是该块的值 + +```move= +fun double_and_add(x: u64, y: u64): u64 { + let double_x = x * 2; + let double_y = y * 2; + double_x + double_y +} +``` + +The return value here is `double_x + double_y` + +这里的返回值为 double_x + double_y + +### `return` expression + +A function implicitly returns the value that its body evaluates to. However, functions can also use the explicit `return` expression: + +### 返回表达式 + +函数隐式返回其主体计算的值。但是,函数也可以使用显式返回表达式: + +```move +fun f1(): u64 { return 0 } +fun f2(): u64 { 0 } +``` + +These two functions are equivalent. In this slightly more involved example, the function subtracts two `u64` values, but returns early with `0` if the second value is too large: + +这两个功能是等价的。在这个稍微复杂的示例中,该函数减去两个 u64 值,但如果第二个值太大,则提前返回 0: + +```move= +fun safe_sub(x: u64, y: u64): u64 { + if (y > x) return 0; + x - y +} +``` + +Note that the body of this function could also have been written as `if (y > x) 0 else x - y`. + +However `return` really shines is in exiting deep within other control flow constructs. In this example, the function iterates through a vector to find the index of a given value: + +请注意,这个函数的主体也可以写成 if (y x) 0 else x - y。 + +然而 return 真正闪耀的是在其他控制流结构的深处退出。在此示例中,函数遍历向量以查找给定值的索引: + +```move= +use std::vector; +use std::option::{Self, Option}; +fun index_of(v: &vector, target: &T): Option { + let i = 0; + let n = vector::length(v); + while (i < n) { + if (vector::borrow(v, i) == target) return option::some(i); + i = i + 1 + }; + + option::none() +} +``` + +Using `return` without an argument is shorthand for `return ()`. That is, the following two functions are equivalent: + +使用不带参数的 return 是 return () 的简写。即以下两个函数是等价的: + +```move +fun foo() { return } +fun foo() { return () } +``` diff --git a/language/documentation/book/translations/move-book-zh/src/generics.md b/language/documentation/book/translations/move-book-zh/src/generics.md new file mode 100644 index 0000000000..8677e4cbec --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/generics.md @@ -0,0 +1,566 @@ +# Generics + +Generics can be used to define functions and structs over different input data types. This language feature is sometimes referred to as *parametric polymorphism*. In Move, we will often use the term generics interchangeably with type parameters and type arguments. + +Generics are commonly used in library code, such as in vector, to declare code that works over any possible instantiation (that satisfies the specified constraints). In other frameworks, generic code can sometimes be used to interact with global storage many different ways that all still share the same implementation. +# 泛型 +泛型可用于定义不同输入数据类型的函数和结构。这种语言特性有时被称为参数多态性。在 Move 中,我们经常将术语泛型与类型参数和类型参数互换使用。 + +泛型通常用于库代码中,例如向量中,以声明适用于任何可能的实例化(满足指定约束)的代码。在其他框架中,通用代码有时可用于与全局存储进行交互,这些方式有很多不同的方式,它们仍然共享相同的实现。 + +## Declaring Type Parameters + +Both functions and structs can take a list of type parameters in their signatures, enclosed by a pair of angle brackets `<...>`. +## 声明类型参数 +函数和结构都可以在其签名中采用类型参数列表,并用一对尖括号 `<...>` 括起来。 + +### Generic Functions + +Type parameters for functions are placed after the function name and before the (value) parameter list. The following code defines a generic identity function that takes a value of any type and returns that value unchanged. +### 泛型函数 +函数的类型参数放在函数名称之后和(值)参数列表之前。以下代码定义了一个通用标识函数,该函数接受任何类型的值并返回该值不变。 + +```move +fun id(x: T): T { + // this type annotation is unnecessary but valid + (x: T) +} +``` + +Once defined, the type parameter `T` can be used in parameter types, return types, and inside the function body. + +一旦定义,类型参数 T 可以在参数类型、返回类型和函数体内部使用。 + +### Generic Structs + +Type parameters for structs are placed after the struct name, and can be used to name the types of the fields. +### 通用结构 +结构的类型参数放在结构名称之后,可用于命名字段的类型。 + +```move +struct Foo has copy, drop { x: T } + +struct Bar has copy, drop { + x: T1, + y: vector, +} +``` + +[Note that type parameters do not have to be used](#unused-type-parameters) + +请注意,不必使用类型参数 + +## Type Arguments + +### Calling Generic Functions + +When calling a generic function, one can specify the type arguments for the function's type parameters in a list enclosed by a pair of angle brackets. +## 类型参数 +### 调用泛型函数 +调用泛型函数时,可以在由一对尖括号括起来的列表中指定函数类型参数的类型参数。 + +```move= +fun foo() { + let x = id(true); +} +``` + +If you do not specify the type arguments, Move's [type inference](#type-inference) will supply them for you. +如果您不指定类型参数,Move 的类型推断将为您提供它们。 + +### Using Generic Structs + +Similarly, one can attach a list of type arguments for the struct's type parameters when constructing or destructing values of generic types. +### 使用通用结构 +类似地,在构造或破坏泛型类型的值时,可以为结构的类型参数附加一个类型参数列表。 + +```move= +fun foo() { + let foo = Foo { x: true }; + let Foo { x } = foo; +} +``` + +If you do not specify the type arguments, Move's [type inference](#type-inference) will supply them for you. +如果您不指定类型参数,Move 的类型推断将为您提供它们。 + +### Type Argument Mismatch + +If you specify the type arguments and they conflict with the actual values supplied, an error will be given +### 类型参数不匹配 +如果您指定类型参数并且它们与提供的实际值冲突,则会给出错误 + +```move= +fun foo() { + let x = id(true); // error! true is not a u64 +} +``` + +and similarly + +同样地 + +```move= +fun foo() { + let foo = Foo { x: 0 }; // error! 0 is not a bool + let Foo

{ x } = foo; // error! bool is incompatible with address +} +``` + +## Type Inference + +In most cases, the Move compiler will be able to infer the type arguments so you don't have to write them down explicitly. Here's what the examples above would look like if we omit the type arguments. +## 类型推断 +在大多数情况下,Move 编译器将能够推断类型参数,因此您不必显式地写下它们。如果我们省略类型参数,这就是上面的示例的样子。 + +```move= +fun foo() { + let x = id(true); + // ^ is inferred + + let foo = Foo { x: true }; + // ^ is inferred + + let Foo { x } = foo; + // ^ is inferred +} +``` + +Note: when the compiler is unable to infer the types, you'll need annotate them manually. A common scenario is to call a function with type parameters appearing only at return positions. + +注意:当编译器无法推断类型时,您需要手动注释它们。一个常见的场景是调用一个类型参数只出现在返回位置的函数。 + +```move= +address 0x2 { +module m { + using std::vector; + + fun foo() { + // let v = vector::new(); + // ^ The compiler cannot figure out the element type. + + let v = vector::new(); + // ^~~~~ Must annotate manually. + } +} +} +``` + +However, the compiler will be able to infer the type if that return value is used later in that function + +但是,如果稍后在该函数中使用该返回值,编译器将能够推断类型 + +```move= +address 0x2 { +module m { + using std::vector; + + fun foo() { + let v = vector::new(); + // ^ is inferred + vector::push_back(&mut v, 42); + } +} +} +``` + +## Unused Type Parameters + +For a struct definition, +an unused type parameter is one that +does not appear in any field defined in the struct, +but is checked statically at compile time. +Move allows unused type parameters so the following struct definition is valid: +## 未使用的类型参数 +对于结构定义,未使用的类型参数是没有出现在结构中定义的任何字段中,但在编译时静态检查的类型参数。 Move 允许未使用的类型参数,因此以下结构定义有效: + +```move= +struct Foo { + foo: u64 +} +``` + +This can be convenient when modeling certain concepts. Here is an example: + +这在对某些概念进行建模时会很方便。这是一个例子: + +```move= +address 0x2 { +module m { + // Currency Specifiers + struct Currency1 {} + struct Currency2 {} + + // A generic coin type that can be instantiated using a currency + // specifier type. + // e.g. Coin, Coin etc. + struct Coin has store { + value: u64 + } + + // Write code generically about all currencies + public fun mint_generic(value: u64): Coin { + Coin { value } + } + + // Write code concretely about one currency + public fun mint_concrete(value: u64): Coin { + Coin { value } + } +} +} +``` + +In this example, +`struct Coin` is generic on the `Currency` type parameter, +which specifies the currency of the coin and +allows code to be written either +generically on any currency or +concretely on a specific currency. +This genericity applies even when the `Currency` type parameter +does not appear in any of the fields defined in `Coin`. + +在此示例中,struct Coin Currency 是 Currency 类型参数的通用结构,该参数指定硬币的货币,并允许将代码一般地写入任何货币或具体地写入特定货币。即使货币类型参数未出现在 Coin 中定义的任何字段中,这种通用性也适用。 + +### Phantom Type Parameters + +In the example above, +although `struct Coin` asks for the `store` ability, +neither `Coin` nor `Coin` will have the `store` ability. +This is because of the rules for +[Conditional Abilities and Generic Types](./abilities.md#conditional-abilities-and-generic-types) +and the fact that `Currency1` and `Currency2` don't have the `store` ability, +despite the fact that they are not even used in the body of `struct Coin`. +This might cause some unpleasant consequences. +For example, we are unable to put `Coin` into a wallet in the global storage. + +One possible solution would be to +add spurious ability annotations to `Currency1` and `Currency2` +(i.e., `struct Currency1 has store {}`). +But, this might lead to bugs or security vulnerabilities +because it weakens the types with unnecessary ability declarations. +For example, we would never expect a resource in the global storage to have a field in type `Currency1`, +but this would be possible with the spurious `store` ability. +Moreover, the spurious annotations would be infectious, +requiring many functions generic on the unused type parameter to also include the necessary constraints. + +Phantom type parameters solve this problem. +Unused type parameters can be marked as *phantom* type parameters, +which do not participate in the ability derivation for structs. +In this way, +arguments to phantom type parameters are not considered when deriving the abilities for generic types, +thus avoiding the need for spurious ability annotations. +For this relaxed rule to be sound, +Move's type system guarantees that a parameter declared as phantom is either +not used at all in the struct definition, or +it is only used as an argument to type parameters also declared as phantom. +### 幻影类型参数 +在上面的例子中,虽然 struct Coin 要求存储能力,但 Coin Currency1 和 Coin Currency2 都没有存储能力。这是因为 Conditional Abilities 和 Generic Types 的规则以及 Currency1 和 Currency2 没有存储能力的事实,尽管它们甚至没有在 struct Coin 的主体中使用。这可能会导致一些不愉快的后果。例如,我们无法将 Coin Currency1 放入全局存储中的钱包。 + +一种可能的解决方案是向 Currency1 和 Currency2 添加虚假的能力注释(即,struct Currency1 具有存储 {})。但是,这可能会导致错误或安全漏洞,因为它会削弱具有不必要能力声明的类型。例如,我们永远不会期望全局存储中的资源具有 Currency1 类型的字段,但是这可以通过虚假存储功能实现。此外,虚假注释具有传染性,需要在未使用的类型参数上泛型的许多函数也包括必要的约束。 + +Phantom 类型参数解决了这个问题。未使用的类型参数可以标记为幻像类型参数,不参与结构的能力推导。这样,在派生泛型类型的能力时,不考虑幻像类型参数的参数,从而避免了对虚假能力注释的需要。为了使这个宽松的规则合理,Move 的类型系统保证声明为 phantom 的参数要么在结构定义中根本不使用,要么仅用作也声明为 phantom 的类型参数的参数。 + +#### Declaration + +In a struct definition +a type parameter can be declared as phantom by adding the `phantom` keyword before its declaration. +If a type parameter is declared as phantom we say it is a phantom type parameter. +When defining a struct, Move's type checker ensures that every phantom type parameter is either +not used inside the struct definition or +it is only used as an argument to a phantom type parameter. + +More formally, +if a type is used as an argument to a phantom type parameter +we say the type appears in _phantom position_. +With this definition in place, +the rule for the correct use of phantom parameters can be specified as follows: +**A phantom type parameter can only appear in phantom position**. + +The following two examples show valid uses of phantom parameters. +In the first one, +the parameter `T1` is not used at all inside the struct definition. +In the second one, the parameter `T1` is only used as an argument to a phantom type parameter. +#### 声明 +在结构定义中,可以通过在声明之前添加 phantom 关键字来将类型参数声明为 phantom。如果一个类型参数被声明为幻像,我们就说它是幻像类型参数。定义结构时,Move 的类型检查器确保每个幻像类型参数要么不在结构定义中使用,要么仅用作幻像类型参数的参数。 + +更正式地说,如果将类型用作幻像类型参数的参数,我们说该类型出现在幻像位置。有了这个定义,正确使用幻像参数的规则可以指定如下:幻像类型参数只能出现在幻像位置。 + +以下两个示例显示了虚拟参数的有效用法。在第一个中,参数 T1 在结构定义中根本没有使用。在第二个中,参数 T1 仅用作幻像类型参数的自变量。 + +```move= +struct S1 { f: u64 } + ^^ + Ok: T1 does not appear inside the struct definition + + +struct S2 { f: S1 } + ^^ + Ok: T1 appears in phantom position +``` + +The following code shows examples of violations of the rule: + +以下代码显示了违反规则的示例: + +```move= +struct S1 { f: T } + ^ + Error: Not a phantom position + +struct S2 { f: T } + +struct S3 { f: S2 } + ^ + Error: Not a phantom position +``` + + +#### Instantiation + +When instantiating a struct, +the arguments to phantom parameters are excluded when deriving the struct abilities. +For example, consider the following code: +#### 实例化 +实例化结构时,派生结构功能时会排除幻像参数的参数。例如,考虑以下代码: + +```move= +struct S has copy { f: T1 } +struct NoCopy {} +struct HasCopy has copy {} +``` + +Consider now the type `S`. +Since `S` is defined with `copy` and all non-phantom arguments have copy +then `S` also has copy. +现在考虑类型 S HasCopy, NoCopy 。由于 S 是用副本定义的,并且所有非幻像参数都有副本,因此 S HasCopy,NoCopy 也有副本。 + +#### Phantom Type Parameters with Ability Constraints + +Ability constraints and phantom type parameters are orthogonal features in the sense that +phantom parameters can be declared with ability constraints. +When instantiating a phantom type parameter with an ability constraint, +the type argument has to satisfy that constraint, +even though the parameter is phantom. +For example, the following definition is perfectly valid: +#### 具有能力约束的幻影类型参数 +能力约束和幻影类型参数是正交特征,因为幻影参数可以用能力约束声明。当使用能力约束实例化一个幻像类型参数时,类型参数必须满足该约束,即使参数是幻像。例如,以下定义是完全有效的: + +```move= +struct S {} +``` + +The usual restrictions apply and `T` can only be instantiated with arguments having `copy`. + +通常的限制适用并且 T 只能用具有副本的参数实例化。 + +## Constraints + +In the examples above, we have demonstrated how one can use type parameters to define "unknown" types that can be plugged in by callers at a later time. This however means the type system has little information about the type and has to perform checks in a very conservative way. In some sense, the type system must assume the worst case scenario for an unconstrained generic. Simply put, by default generic type parameters have no [abilities](./abilities.md). + +This is where constraints come into play: they offer a way to specify what properties these unknown types have so the type system can allow operations that would otherwise be unsafe. +## 约束 +在上面的例子中,我们已经演示了如何使用类型参数来定义“未知”类型,这些类型可以在稍后被调用者插入。然而,这意味着类型系统几乎没有关于类型的信息,并且必须以非常保守的方式执行检查。从某种意义上说,类型系统必须假设不受约束的泛型的最坏情况。简单地说,默认情况下泛型类型参数没有能力。 + +这就是约束发挥作用的地方:它们提供了一种方法来指定这些未知类型具有哪些属性,因此类型系统可以允许原本不安全的操作。 + +### Declaring Constraints + +Constraints can be imposed on type parameters using the following syntax. +### 声明约束 +可以使用以下语法对类型参数施加约束。 + +```move= +// T is the name of the type parameter +T: (+ )* +``` + +The `` can be any of the four [abilities](./abilities.md), and a type parameter can be constrained with multiple [abilities](./abilities.md) at once. So all of the following would be valid type parameter declarations + +能力可以是四种能力中的任何一种,一个类型参数可以同时被多个能力约束。因此,以下所有内容都是有效的类型参数声明 + +```move +T: copy +T: copy + drop +T: copy + drop + store + key +``` + +### Verifying Constraints + +Constraints are checked at call sites so the following code won't compile. +### 验证约束 +在调用站点检查约束,因此无法编译以下代码。 + +```move= +struct Foo { x: T } + +struct Bar { x: Foo } +// ^ error! u8 does not have 'key' + +struct Baz { x: Foo } +// ^ error! T does not have 'key' +``` + +```move= +struct R {} + +fun unsafe_consume(x: T) { + // error! x does not have 'drop' +} + +fun consume(x: T) { + // valid! + // x will be dropped automatically +} + +fun foo() { + let r = R {}; + consume(r); + // ^ error! R does not have 'drop' +} +``` + +```move= +struct R {} + +fun unsafe_double(x: T) { + (copy x, x) + // error! x does not have 'copy' +} + +fun double(x: T) { + (copy x, x) // valid! +} + +fun foo(): (R, R) { + let r = R {}; + double(r) + // ^ error! R does not have copy +} +``` + +For more information, see the abilities section on [conditional abilities and generic types](./abilities.html#conditional-abilities-and-generic-types) + +有关更多信息,请参阅有关条件能力和泛型类型的能力部分 + +## Limitations on Recursions + +### Recursive Structs + +Generic structs can not contain fields of the same type, either directly or indirectly, even with different type arguments. All of the following struct definitions are invalid: +## 递归的限制 +### 递归结构 +通用结构不能直接或间接包含相同类型的字段,即使使用不同的类型参数也是如此。以下所有结构定义均无效: + +```move= +struct Foo { + x: Foo // error! 'Foo' containing 'Foo' +} + +struct Bar { + x: Bar // error! 'Bar' containing 'Bar' +} + +// error! 'A' and 'B' forming a cycle, which is not allowed either. +struct A { + x: B +} + +struct B { + x: A + y: A +} +``` + +### Advanced Topic: Type-level Recursions + +Move allows generic functions to be called recursively. However, when used in combination with generic structs, this could create an infinite number of types in certain cases, and allowing this means adding unnecessary complexity to the compiler, vm and other language components. Therefore, such recursions are forbidden. + +Allowed: +### 高级主题:类型级递归 +Move 允许递归调用泛型函数。但是,当与泛型结构结合使用时,在某些情况下可能会创建无限数量的类型,并且允许这意味着给编译器、vm 和其他语言组件增加不必要的复杂性。因此,这种递归是被禁止的。 + +允许: + +```move= +address 0x2 { +module m { + struct A {} + + // Finitely many types -- allowed. + // foo -> foo -> foo -> ... is valid + fun foo() { + foo(); + } + + // Finitely many types -- allowed. + // foo -> foo> -> foo> -> ... is valid + fun foo() { + foo>(); + } +} +} +``` + +Not allowed: + +不允许: + +```move= +address 0x2 { +module m { + struct A {} + + // Infinitely many types -- NOT allowed. + // error! + // foo -> foo> -> foo>> -> ... + fun foo() { + foo>(); + } +} +} +``` + +```move= +address 0x2 { +module n { + struct A {} + + // Infinitely many types -- NOT allowed. + // error! + // foo -> bar -> foo> + // -> bar, T2> -> foo, A> + // -> bar, A> -> foo, A>> + // -> ... + fun foo() { + bar(); + } + + fun bar { + foo>(); + } +} +} +``` + +Note, the check for type level recursions is based on a conservative analysis on the call sites and does NOT take control flow or runtime values into account. + +请注意,类型级别递归的检查是基于对调用站点的保守分析,并且不考虑控制流或运行时值。 + +```move= +address 0x2 { +module m { + struct A {} + + fun foo(n: u64) { + if (n > 0) { + foo>(n - 1); + }; + } +} +} +``` + +The function in the example above will technically terminate for any given input and therefore only creating finitely many types, but it is still considered invalid by Move's type system. + +上例中的函数将在技术上终止任何给定的输入,因此只会创建有限多个类型,但 Move 的类型系统仍然认为它是无效的。 diff --git a/language/documentation/book/translations/move-book-zh/src/global-storage-operators.md b/language/documentation/book/translations/move-book-zh/src/global-storage-operators.md new file mode 100644 index 0000000000..80238a0d9c --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/global-storage-operators.md @@ -0,0 +1,305 @@ +# Global Storage - Operators + +Move programs can create, delete, and update [resources](./structs-and-resources.md) in global storage using the following five instructions: +# 全球存储 - 操作符 +移动程序可以使用以下五个指令在全局存储中创建、删除和更新资源: + + +| Operation | Description | Aborts? | +---------------------------------------- |---------------------------------------------------------------- |---------------------------------------- | +|`move_to(&signer,T)` | Publish `T` under `signer.address` | If `signer.address` already holds a `T` | +|`move_from(address): T` | Remove `T` from `address` and return it | If `address` does not hold a `T` | +|`borrow_global_mut(address): &mut T` | Return a mutable reference to the `T` stored under `address` | If `address` does not hold a `T` | +|`borrow_global(address): &T` | Return an immutable reference to the `T` stored under `address` | If `address` does not hold a `T` | +|`exists(address): bool` | Return `true` if a `T` is stored under `address` | Never | + + +Each of these instructions is parameterized by a type `T` with the [`key` ability](./abilities.md). However, each type `T` *must be declared in the current module*. This ensures that a resource can only be manipulated via the API exposed by its defining module. The instructions also take either an [`address`](./address.md) or [`&signer`](./signer.md) representing the account address where the resource of type `T` is stored. + +这些指令中的每一个都由具有关键能力的类型 T 参数化。但是,每个类型 T 都必须在当前模块中声明。这确保了资源只能通过其定义模块公开的 API 进行操作。这些指令还采用地址或 &signer 表示存储类型 T 资源的帐户地址。 + +## References to resources + +References to global resources returned by `borrow_global` or `borrow_global_mut` mostly behave like references to local storage: they can be extended, read, and written using ordinary [reference operators](./references.md) and passed as arguments to other function. However, there is one important difference between local and global references: **a function cannot return a reference that points into global storage**. For example, these two functions will each fail to compile: + +## 对资源的引用 +borrow_global 或 borrow_global_mut 返回的对全局资源的引用主要表现为对本地存储的引用:它们可以使用普通的引用运算符进行扩展、读取和写入,并作为参数传递给其他函数。但是,本地引用和全局引用之间有一个重要区别:函数不能返回指向全局存储的引用。例如,这两个函数都将无法编译: + +```move +struct R has key { f: u64 } +// will not compile +fun ret_direct_resource_ref_bad(a: address): &R { + borrow_global(a) // error! +} +// also will not compile +fun ret_resource_field_ref_bad(a: address): &u64 { + &borrow_global(a).f // error! +} +``` + +Move must enforce this restriction to guarantee absence of dangling references to global storage. [This](#reference-safety-for-global-resources) section contains much more detail for the interested reader. + +Move 必须强制执行此限制以保证不存在对全局存储的悬空引用。本节为感兴趣的读者提供了更多详细信息。 + +## Global storage operators with generics + +Global storage operations can be applied to generic resources with both instantiated and uninstantiated generic type parameters: + +## 具有泛型的全局存储运算符 +全局存储操作可以应用于具有实例化和未实例化的泛型类型参数的泛型资源: + +```move +struct Container has key { t: T } + +// Publish a Container storing a type T of the caller's choosing +fun publish_generic_container(account: &signer, t: T) { + move_to>(account, Container { t }) +} + +/// Publish a container storing a u64 +fun publish_instantiated_generic_container(account: &signer, t: u64) { + move_to>(account, Container { t }) +} +``` + +The ability to index into global storage via a type parameter chosen at runtime is a powerful Move feature known as *storage polymorphism*. For more on the design patterns enabled by this feature, see [Move generics](./generics.md). + +通过在运行时选择的类型参数对全局存储进行索引的能力是一种强大的移动功能,称为存储多态性。有关此功能启用的设计模式的更多信息,请参阅移动泛型。 + +## Example: `Counter` + +The simple `Counter` module below exercises each of the five global storage operators. The API exposed by this module allows: + +- Anyone to publish a `Counter` resource under their account +- Anyone to check if a `Counter` exists under any address +- Anyone to read or increment the value of a `Counter` resource under any address +- An account that stores a `Counter` resource to reset it to zero +- An account that stores a `Counter` resource to remove and delete it + +## 示例:计数器 +下面的简单 Counter 模块练习了五个全局存储运算符中的每一个。该模块公开的 API 允许: + +- 任何人都可以在其帐户下发布 Counter 资源 +- 任何人都可以检查任何地址下是否存在计数器 +- 任何人都可以读取或增加任何地址下的 Counter 资源的值 +- 存储计数器资源以将其重置为零的帐户 +- 存储 Counter 资源以移除和删除它的帐户 + +```move +address 0x42 { +module counter { + use std::signer; + + /// Resource that wraps an integer counter + struct Counter has key { i: u64 } + + /// Publish a `Counter` resource with value `i` under the given `account` + public fun publish(account: &signer, i: u64) { + // "Pack" (create) a Counter resource. This is a privileged operation that + // can only be done inside the module that declares the `Counter` resource + move_to(account, Counter { i }) + } + + /// Read the value in the `Counter` resource stored at `addr` + public fun get_count(addr: address): u64 acquires Counter { + borrow_global(addr).i + } + + /// Increment the value of `addr`'s `Counter` resource + public fun increment(addr: address) acquires Counter { + let c_ref = &mut borrow_global_mut(addr).i; + *c_ref = *c_ref + 1 + } + + /// Reset the value of `account`'s `Counter` to 0 + public fun reset(account: &signer) acquires Counter { + let c_ref = &mut borrow_global_mut(signer::address_of(account)).i; + *c_ref = 0 + } + + /// Delete the `Counter` resource under `account` and return its value + public fun delete(account: &signer): u64 acquires Counter { + // remove the Counter resource + let c = move_from(signer::address_of(account)); + // "Unpack" the `Counter` resource into its fields. This is a + // privileged operation that can only be done inside the module + // that declares the `Counter` resource + let Counter { i } = c; + i + } + + /// Return `true` if `addr` contains a `Counter` resource + public fun exists(addr: address): bool { + exists(addr) + } +} +} +``` + +## Annotating functions with `acquires` + +In the `counter` example, you might have noticed that the `get_count`, `increment`, `reset`, and `delete` functions are annotated with `acquires Counter`. A Move function `m::f` must be annotated with `acquires T` if and only if: + +- The body of `m::f` contains a `move_from`, `borrow_global_mut`, or `borrow_global` instruction, or +- The body of `m::f` invokes a function `m::g` declared in the same module that is annotated with `acquires` + +For example, the following function inside `Counter` would need an `acquires` annotation: + +## 使用获取注释函数 +在 counter 示例中,您可能已经注意到 get_count、increment、reset 和 delete 函数都使用 acquire Counter 进行注释。移动函数 m::f 必须用获取 T 注释当且仅当: + +- m::f 的主体包含 move_from T 、 borrow_global_mut T 或 borrow_global T 指令,或 +- m::f 的主体调用在同一个模块中声明的函数 m::g +例如,Counter 中的以下函数需要一个获取注解: + +```move +// Needs `acquires` because `increment` is annotated with `acquires` +fun call_increment(addr: address): u64 acquires Counter { + counter::increment(addr) +} +``` + +However, the same function *outside* `Counter` would not need an annotation: + +但是,Counter 之外的相同函数不需要注释: + +```move +address 0x43 { +module m { + use 0x42::counter; + + // Ok. Only need annotation when resource acquired by callee is declared + // in the same module + fun call_increment(addr: address): u64 { + counter::increment(addr) + } +} +} +``` + +If a function touches multiple resources, it needs multiple `acquires`: + +如果一个函数涉及多个资源,它需要多次获取: + +```move= +address 0x42 { +module two_resources { + struct R1 has key { f: u64 } + struct R2 has key { g: u64 } + + fun double_acquires(a: address): u64 acquires R1, R2 { + borrow_global(a).f + borrow_global.g + } +} +} +``` + +The `acquires` annotation does not take generic type parameters into account: + +获取注解不考虑泛型类型参数: + +```move= +address 0x42 { +module m { + struct R has key { t: T } + + // `acquires R`, not `acquires R` + fun acquire_generic_resource(a: addr) acquires R { + let _ = borrow_global>(a); + } + + // `acquires R`, not `acquires R + fun acquire_instantiated_generic_resource(a: addr) acquires R { + let _ = borrow_global>(a); + } +} +} +``` + +Finally: redundant `acquires` are not allowed. Adding this function inside `Counter` will result in a compilation error: + +最后:不允许冗余获取。在 Counter 中添加这个函数会导致编译错误: + +```move +// This code will not compile because the body of the function does not use a global +// storage instruction or invoke a function with `acquires` +fun redundant_acquires_bad() acquires Counter {} +``` + +For more information on `acquires`, see [Move functions](./functions.md). + +有关获取的更多信息,请参阅移动函数。 + +## Reference Safety For Global Resources + +Move prohibits returning global references and requires the `acquires` annotation to prevent dangling references. This allows Move to live up to its promise of static reference safety (i.e., no dangling references, no `null` or `nil` dereferences) for all [reference](./references.md) types. + +This example illustrates how the Move type system uses `acquires` to prevent a dangling reference: + +## 全局资源的引用安全 +Move 禁止返回全局引用,并要求获取注解以防止悬空引用。这允许 Move 兑现其对所有引用类型的静态引用安全的承诺(即,没有悬空引用,没有 null 或 nil 取消引用)。 + +此示例说明了 Move 类型系统如何使用获取来防止悬空引用: + +```move= +address 0x42 { +module dangling { + struct T has key { f: u64 } + + fun borrow_then_remove_bad(a: address) acquires T { + let t_ref: &mut T = borrow_global_mut(a); + let t = remove_t(a); // type system complains here + // t_ref now dangling! + let uh_oh = *&t_ref.f + } + + fun remove_t(a: address): T acquires T { + move_from(a) + } + +} +} +``` + +In this code, line 6 acquires a reference to the `T` stored at address `a` in global storage. The callee `remove_t` then removes the value, which makes `t_ref` a dangling reference. + +Fortunately, this cannot happen because the type system will reject this program. The `acquires` annotation on `remove_t` lets the type system know that line 7 is dangerous, without having to recheck or introspect the body of `remove_t` separately! + +The restriction on returning global references prevents a similar, but even more insidious problem: + +在此代码中,第 6 行获取对存储在全局存储中地址 a 处的 T 的引用。被调用者 remove_t 然后删除该值,这使 t_ref 成为悬空引用。 + +幸运的是,这不可能发生,因为类型系统会拒绝这个程序。 remove_t 上的 acquires 注释让类型系统知道第 7 行是危险的,而无需单独重新检查或反省 remove_t 的主体! + +对返回全局引用的限制防止了类似但更隐蔽的问题: + +```move= +address 0x42 { +module m1 { + struct T has key {} + + public fun ret_t_ref(a: address): &T acquires T { + borrow_global(a) // error! type system complains here + } + + public fun remove_t(a: address) acquires T { + let T {} = move_from(a); + } +} + +module m2 { + fun borrow_then_remove_bad(a: address) { + let t_ref = m1::ret_t_ref(a); + let t = m1::remove_t(a); // t_ref now dangling! + } +} +} +``` + +Line 16 acquires a reference to a global resource `m1::T`, then line 17 removes that same resource, which makes `t_ref` dangle. In this case, `acquires` annotations do not help us because the `borrow_then_remove_bad` function is outside of the `m1` module that declares `T` (recall that `acquires` annotations can only be used for resources declared in the current module). Instead, the type system avoids this problem by preventing the return of a global reference at line 6. + +Fancier type systems that would allow returning global references without sacrificing reference safety are possible, and we may consider them in future iterations of Move. We chose the current design because it strikes a good balance between expressivity, annotation burden, and type system complexity. + +第 16 行获取对全局资源 m1::T 的引用,然后第 17 行删除相同的资源,这使得 t_ref 悬空。在这种情况下,获取注解对我们没有帮助,因为 borrow_then_remove_bad 函数位于声明 T 的 m1 模块之外(回想一下,获取注解只能用于在当前模块中声明的资源)。相反,类型系统通过阻止在第 6 行返回全局引用来避免这个问题。 + +在不牺牲引用安全的情况下允许返回全局引用的更高级的类型系统是可能的,我们可能会在 Move 的未来迭代中考虑它们。我们选择了当前的设计,因为它在表现力、注释负担和类型系统复杂性之间取得了很好的平衡。 diff --git a/language/documentation/book/translations/move-book-zh/src/global-storage-structure.md b/language/documentation/book/translations/move-book-zh/src/global-storage-structure.md new file mode 100644 index 0000000000..240dfc3b2c --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/global-storage-structure.md @@ -0,0 +1,21 @@ +# Global Storage - Structure + +The purpose of Move programs is to [read from and write to](./global-storage-operators.md) tree-shaped persistent global storage. Programs cannot access the filesystem, network, or any other data outside of this tree. + +In pseudocode, the global storage looks something like + +# 全局存储 - 结构 +Move 程序的目的是读取和写入树形持久全局存储。程序无法访问此树之外的文件系统、网络或任何其他数据。 + +在伪代码中,全局存储看起来像 + +```move +struct GlobalStorage { + resources: Map<(address, ResourceType), ResourceValue> + modules: Map<(address, ModuleName), ModuleBytecode> +} +``` + +Structurally, global storage is a [forest](https://en.wikipedia.org/wiki/Tree_(graph_theory)) consisting of trees rooted at an account [`address`](./address.md). Each address can store both [resource](./structs-and-resources.md) data values and [module](./modules-and-scripts.md) code values. As the pseudocode above indicates, each `address` can store at most one resource value of a given type and at most one module with a given name. + +从结构上讲,全局存储是一个由植根于帐户地址的树组成的森林。每个地址都可以存储资源数据值和模块代码值。如上面的伪代码所示,每个地址最多可以存储一个给定类型的资源值和一个给定名称的模块。 diff --git a/language/documentation/book/translations/move-book-zh/src/integers.md b/language/documentation/book/translations/move-book-zh/src/integers.md new file mode 100644 index 0000000000..e65e584a8f --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/integers.md @@ -0,0 +1,176 @@ +# Integers + +Move supports three unsigned integer types: `u8`, `u64`, and `u128`. Values of these types range from 0 to a maximum that depends on the size of the type. +# 整数 +Move 支持三种无符号整数类型:u8、u64 和 u128。这些类型的值范围从 0 到最大值,具体取决于类型的大小。 + +| Type | Value Range | +| -------------------------------- | ------------------------ | +| Unsigned 8-bit integer, `u8` | 0 to 28 - 1 | +| Unsigned 64-bit integer, `u64` | 0 to 264 - 1 | +| Unsigned 128-bit integer, `u128` | 0 to 2128 - 1 | + +## Literals + +Literal values for these types are specified either as a sequence of digits (e.g.,`112`) or as hex literals, e.g., `0xFF`. The type of the literal can optionally be added as a suffix, e.g., `112u8`. If the type is not specified, the compiler will try to infer the type from the context where the literal is used. If the type cannot be inferred, it is assumed to be `u64`. + +If a literal is too large for its specified (or inferred) size range, an error is reported. +## 字面量 +这些类型的文字值指定为数字序列(例如,112)或十六进制文字,例如,0xFF。可以选择将文字的类型添加为后缀,例如 112u8。如果未指定类型,编译器将尝试从使用文字的上下文推断类型。如果无法推断类型,则假定为 u64。 + +如果文字对于其指定的(或推断的)大小范围来说太大,则会报告错误。 + +### Examples +### 例子 + +```move +// literals with explicit annotations; +let explicit_u8 = 1u8; +let explicit_u64 = 2u64; +let explicit_u128 = 3u128; + +// literals with simple inference +let simple_u8: u8 = 1; +let simple_u64: u64 = 2; +let simple_u128: u128 = 3; + +// literals with more complex inference +let complex_u8 = 1; // inferred: u8 +// right hand argument to shift must be u8 +let _unused = 10 << complex_u8; + +let x: u8 = 0; +let complex_u8 = 2; // inferred: u8 +// arguments to `+` must have the same type +let _unused = x + complex_u8; + +let complex_u128 = 3; // inferred: u128 +// inferred from function argument type +function_that_takes_u128(complex_u128); + +// literals can be written in hex +let hex_u8: u8 = 0x1; +let hex_u64: u64 = 0xCAFE; +let hex_u128: u128 = 0xDEADBEEF; +``` + +## Operations + +### Arithmetic + +Each of these types supports the same set of checked arithmetic operations. For all of these operations, both arguments (the left and right side operands) *must* be of the same type. If you need to operate over values of different types, you will need to first perform a [cast](#casting). Similarly, if you expect the result of the operation to be too large for the integer type, perform a [cast](#casting) to a larger size before performing the operation. + +All arithmetic operations abort instead of behaving in a way that mathematical integers would not (e.g., overflow, underflow, divide-by-zero). +## 运营 +### 算术 +这些类型中的每一种都支持相同的检查算术运算集。对于所有这些操作,两个参数(左侧和右侧操作数)必须是同一类型。如果您需要对不同类型的值进行操作,则需要首先执行强制转换。同样,如果您预计运算结果对于整数类型来说太大,请在执行运算之前执行转换为更大的大小。 + +所有算术运算都会中止,而不是以数学整数不会的方式表现(例如,上溢、下溢、被零除)。 + +| Syntax | Operation | Aborts If +|--------|-----------|------------------------------------- +| `+` |addition | Result is too large for the integer type +| `-` | subtraction | Result is less than zero +| `*` | multiplication | Result is too large for the integer type +| `%` | modular division | The divisor is `0` +| `/` | truncating division | The divisor is `0` + + +### Bitwise + +The integer types support the following bitwise operations that treat each number as a series of individual bits, either 0 or 1, instead of as numerical integer values. + +Bitwise operations do not abort. +### 按位 +整数类型支持以下按位运算,将每个数字视为一系列单独的位,0 或 1,而不是数字整数值。 + +按位运算不会中止。 + +| Syntax | Operation | Description +|--------|------------|------------ +| `&` | bitwise and| Performs a boolean and for each bit pairwise +| `|` | bitwise or | Performs a boolean or for each bit pairwise +| `^` | bitwise xor| Performs a boolean exclusive or for each bit pairwise + +### Bit Shifts + +Similar to the bitwise operations, each integer type supports bit shifts. But unlike the other operations, the righthand side operand (how many bits to shift by) must *always* be a `u8` and need not match the left side operand (the number you are shifting). + +Bit shifts can abort if the number of bits to shift by is greater than or equal to `8`, `64`, or `128` for `u8`, `u64`, and `u128` respectively. +### 位移 +与按位运算类似,每种整数类型都支持位移。但与其他操作不同,右侧操作数(要移位多少位)必须始终是 u8 并且不需要匹配左侧操作数(您要移位的数字)。 + +如果要移位的位数分别大于或等于 u8、u64 和 u128 的 8、64 或 128,则移位可以中止。 + +| Syntax | Operation | Aborts if +|--------|------------|---------- +|`<<` | shift left | Number of bits to shift by is greater than the size of the integer type +|`>>` | shift right| Number of bits to shift by is greater than the size of the integer type + +### Comparisons + +Integer types are the *only* types in Move that can use the comparison operators. Both arguments need to be of the same type. If you need to compare integers of different types, you will need to [cast](#casting) one of them first. + +Comparison operations do not abort. +### 比较 +整数类型是 Move 中唯一可以使用比较运算符的类型。两个参数必须是同一类型。如果您需要比较不同类型的整数,则需要先转换其中一个。 + +比较操作不会中止。 + +| Syntax | Operation +|--------|----------- +| `<` | less than +| `>` | greater than +| `<=` | less than or equal to +| `>=` | greater than or equal to + +### Equality + +Like all types with [`drop`](./abilities.md) in Move, all integer types support the ["equal"](./equality.md) and ["not equal"](./equality.md) operations. Both arguments need to be of the same type. If you need to compare integers of different types, you will need to [cast](#casting) one of them first. + +Equality operations do not abort. +### 平等 +与 Move 中的所有类型一样,所有整数类型都支持“等于”和“不等于”操作。两个参数必须是同一类型。如果您需要比较不同类型的整数,则需要先转换其中一个。 + +平等操作不会中止。 + +| Syntax | Operation +|--------|---------- +| `==` | equal +| `!=` | not equal + +For more details see the section on [equality](./equality.md) + +有关更多详细信息,请参阅平等部分 + +## Casting + +Integer types of one size can be cast to integer types of another size. Integers are the only types in Move that support casting. + +Casts *do not* truncate. Casting will abort if the result is too large for the specified type +## 铸件 +一种大小的整数类型可以转换为另一种大小的整数类型。整数是 Move 中唯一支持强制转换的类型。 + +强制转换不会截断。如果结果对于指定类型来说太大,则转换将中止 + +| Syntax | Operation | Aborts if +|------------|---------------------------------------------------------------------------------|--------------------------------------- +| `(e as T)`| Cast integer expression `e` into an integer type `T` | `e` is too large to represent as a `T` + +Here, the type of `e` must be `u8`, `u64`, or `u128` and `T` must be `u8`, `u64`, or `u128`. + +For example: + +这里,e 的类型必须是 u8、u64 或 u128,T 必须是 u8、u64 或 u128。 + +例如: + +- `(x as u8)` +- `(2u8 as u64)` +- `(1 + 3 as u128)` + +## Ownership + +As with the other scalar values built-in to the language, integer values are implicitly copyable, meaning they can be copied without an explicit instruction such as [`copy`](./variables.md#move-and-copy). +## 所有权 +与语言内置的其他标量值一样,整数值是隐式可复制的,这意味着它们可以在没有显式指令(如复制)的情况下复制。 diff --git a/language/documentation/book/translations/move-book-zh/src/introduction.md b/language/documentation/book/translations/move-book-zh/src/introduction.md new file mode 100644 index 0000000000..21a46748f1 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/introduction.md @@ -0,0 +1,49 @@ +# Introduction + +Welcome to Move, a next generation language for secure, sandboxed, and formally verified programming. Its first use case is for the Diem blockchain, where Move provides the foundation for its implementation. Move allows developers to write programs that flexibly manage and transfer assets, while providing the security and protections against attacks on those assets. However, Move has been developed with use cases in mind outside a blockchain context as well. + +Move takes its cue from [Rust](https://www.rust-lang.org/) by using resource types with move (hence the name) semantics as an explicit representation of digital assets, such as currency. +# 介绍 +欢迎使用 Move,这是一种用于安全、沙盒和正式验证的编程的下一代语言。它的第一个用例是 Diem 区块链,Move 为其实施提供了基础。 Move 允许开发人员编写灵活管理和转移资产的程序,同时提供对这些资产的攻击的安全性和保护。然而,Move 的开发也考虑了区块链环境之外的用例。 + +Move 通过使用具有 move(因此得名)语义的资源类型作为数字资产(例如货币)的显式表示,从 Rust 中汲取灵感。 + +## Who is Move for? + +Move was designed and created as a secure, verified, yet flexible programming language. The first use of Move is for the implementation of the Diem blockchain. That said, the language is still evolving. Move has the potential to be a language for other blockchains, and even non-blockchain use cases as well. + +Given custom Move modules will not be supported at the [launch](https://diem.com/white-paper/#whats-next) of the Diem Payment Network (DPN), we are targeting an early Move Developer persona. + +The early Move Developer is one with some programming experience, who wants to begin understanding the core programming language and see examples of its usage. + +## 为谁而动? +Move 被设计和创建为一种安全、经过验证且灵活的编程语言。 Move 的第一个用途是实现 Diem 区块链。也就是说,语言仍在不断发展。 Move 有可能成为其他区块链甚至非区块链用例的语言。 + +鉴于在 Diem 支付网络 (DPN) 启动时将不支持自定义 Move 模块,我们的目标是早期的 Move 开发人员角色。 + +早期的 Move 开发人员是具有一定编程经验的人,他们希望开始了解核心编程语言并查看其使用示例。 + +### Hobbyists + +Understanding that the capability to create custom modules on the Diem Payment Network will not be available at launch, the hobbyist Move Developer is interested in learning the intricacies of the language. She will understand the basic syntax, the standard libraries available, and write example code that can be executed using the Move CLI. The Move Developer may even want to dig into understanding how the Move Virtual Machine executes the code she writes. + +### 爱好者 +了解在 Diem 支付网络上创建自定义模块的功能在发布时将不可用,爱好者 Move 开发人员有兴趣学习该语言的复杂性。她将了解基本语法、可用的标准库,并编写可以使用 Move CLI 执行的示例代码。 Move 开发人员甚至可能想深入了解 Move 虚拟机如何执行她编写的代码。 + +### Core Contributor + +Beyond a hobbyist wanting to stay ahead of the curve for the core programming language is someone who may want to [contribute](https://diem.com/en-US/cla-sign/) directly to Move. Whether this includes submitting language improvements or even, in the future, adding core modules available on the Diem Payment Network, the core contributor will understand Move at a deep level. +### 核心贡献者 +除了想要在核心编程语言方面保持领先的业余爱好者之外,还有可能想要直接为 Move 做出贡献的人。无论这包括提交语言改进,还是将来添加 Diem 支付网络上可用的核心模块,核心贡献者都将深入了解 Move。 + +### Who Move is currently not targeting + +Currently, Move is not targeting developers who wish to create custom modules and contracts for use on the Diem Payment Network. We are also not targeting novice developers who expect a completely polished developer experience even in testing the language. +### 目前未针对谁移动 +目前,Move 不针对希望创建自定义模块和合同以在 Diem 支付网络上使用的开发人员。我们也不针对新手开发者,他们希望即使在测试语言时也能获得完美的开发者体验。 + +## Where Do I Start? + +Begin with understanding [modules and scripts](./modules-and-scripts.md) and then work through the [Move Tutorial](./creating-coins.md). +## 我从哪说起呢? +从了解模块和脚本开始,然后完成移动教程。 diff --git a/language/documentation/book/translations/move-book-zh/src/loops.md b/language/documentation/book/translations/move-book-zh/src/loops.md new file mode 100644 index 0000000000..56b6c6dc72 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/loops.md @@ -0,0 +1,217 @@ +# While and Loop + +Move offers two constructs for looping: `while` and `loop`. +# While 和循环 +Move 提供了两种循环结构:while 和 loop。 + +## `while` loops + +The `while` construct repeats the body (an expression of type unit) until the condition (an expression of type `bool`) evaluates to `false`. + +Here is an example of simple `while` loop that computes the sum of the numbers from `1` to `n`: +## while 循环 +while 构造重复主体(单元类型的表达式),直到条件(布尔类型的表达式)评估为假。 + +下面是一个简单的 while 循环示例,它计算从 1 到 n 的数字之和: + +```move +fun sum(n: u64): u64 { + let sum = 0; + let i = 1; + while (i <= n) { + sum = sum + i; + i = i + 1 + }; + + sum +} +``` + +Infinite loops are allowed: +允许无限循环: + +```move= +fun foo() { + while (true) { } +} +``` + +### `break` + +The `break` expression can be used to exit a loop before the condition evaluates to `false`. For example, this loop uses `break` to find the smallest factor of `n` that's greater than 1: + +### `break` +break 表达式可用于在条件计算为假之前退出循环。例如,此循环使用 break 来查找 n 中大于 1 的最小因子: + +```move +fun smallest_factor(n: u64): u64 { + // assuming the input is not 0 or 1 + let i = 2; + while (i <= n) { + if (n % i == 0) break; + i = i + 1 + }; + + i +} +``` + +The `break` expression cannot be used outside of a loop. + +break 表达式不能在循环外使用。 + +### `continue` + +The `continue` expression skips the rest of the loop and continues to the next iteration. This loop uses `continue` to compute the sum of `1, 2, ..., n`, except when the number is divisible by 10: + +### `continue` +continue 表达式跳过循环的其余部分并继续下一次迭代。此循环使用 continue 来计算 1、2、...、n 的总和,除非该数字能被 10 整除: + +```move +fun sum_intermediate(n: u64): u64 { + let sum = 0; + let i = 0; + while (i < n) { + i = i + 1; + if (i % 10 == 0) continue; + sum = sum + i; + }; + + sum +} +``` + +The `continue` expression cannot be used outside of a loop. +continue 表达式不能在循环外使用。 + +### The type of `break` and `continue` + +`break` and `continue`, much like `return` and `abort`, can have any type. The following examples illustrate where this flexible typing can be helpful: + +### 中断和继续的类型 +break 和 continue 就像 return 和 abort 一样,可以有任何类型。以下示例说明了这种灵活的类型在哪些方面会有所帮助: + +```move +fun pop_smallest_while_not_equal( + v1: vector, + v2: vector, +): vector { + let result = vector::empty(); + while (!vector::is_empty(&v1) && !vector::is_empty(&v2)) { + let u1 = *vector::borrow(&v1, vector::length(&v1) - 1); + let u2 = *vector::borrow(&v2, vector::length(&v2) - 1); + let popped = + if (u1 < u2) vector::pop_back(&mut v1) + else if (u2 < u1) vector::pop_back(&mut v2) + else break; // Here, `break` has type `u64` + vector::push_back(&mut result, popped); + }; + + result +} +``` + +```move +fun pick( + indexes: vector, + v1: &vector
, + v2: &vector
+): vector
{ + let len1 = vector::length(v1); + let len2 = vector::length(v2); + let result = vector::empty(); + while (!vector::is_empty(&indexes)) { + let index = vector::pop_back(&mut indexes); + let chosen_vector = + if (index < len1) v1 + else if (index < len2) v2 + else continue; // Here, `continue` has type `&vector
` + vector::push_back(&mut result, *vector::borrow(chosen_vector, index)) + }; + + result +} +``` + +## The `loop` expression + +The `loop` expression repeats the loop body (an expression with type `()`) until it hits a `break` + +Without a `break`, the loop will continue forever +## 循环表达式 +循环表达式重复循环体(类型为 () 的表达式),直到遇到中断 + +没有中断,循环将永远继续 + +```move +fun foo() { + let i = 0; + loop { i = i + 1 } +} +``` + +Here is an example that uses `loop` to write the `sum` function: + +这是一个使用循环编写求和函数的示例: + +```move +fun sum(n: u64): u64 { + let sum = 0; + let i = 0; + loop { + i = i + 1; + if (i > n) break; + sum = sum + i + }; + + sum +} +``` + +As you might expect, `continue` can also be used inside a `loop`. Here is `sum_intermediate` from above rewritten using `loop` instead of `while` + +如您所料, continue 也可以在循环内使用。这是上面使用循环而不是 while 重写的 sum_intermediate + +```move +fun sum_intermediate(n: u64): u64 { + let sum = 0; + let i = 0; + loop { + i = i + 1; + if (i % 10 == 0) continue; + if (i > n) break; + sum = sum + i + }; + + sum +} +``` + +## The type of `while` and `loop` + +Move loops are typed expressions. A `while` expression always has type `()`. +## while 和循环的类型 +移动循环是类型化的表达式。 while 表达式始终具有 () 类型。 + +```move +let () = while (i < 10) { i = i + 1 }; +``` + +If a `loop` contains a `break`, the expression has type unit `()` + +如果循环包含中断,则表达式的类型为 unit () + +```move +(loop { if (i < 10) i = i + 1 else break }: ()); +let () = loop { if (i < 10) i = i + 1 else break }; +``` + +If `loop` does not have a `break`, `loop` can have any type much like `return`, `abort`, `break`, and `continue`. + +如果循环包含中断,则表达式的类型为 unit () + +```move +(loop (): u64); +(loop (): address); +(loop (): &vector>); +``` diff --git a/language/documentation/book/translations/move-book-zh/src/modules-and-scripts.md b/language/documentation/book/translations/move-book-zh/src/modules-and-scripts.md new file mode 100644 index 0000000000..e44d70ebc4 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/modules-and-scripts.md @@ -0,0 +1,163 @@ +# Modules and Scripts + +Move has two different types of programs: ***Modules*** and ***Scripts***. Modules are libraries that define struct types along with functions that operate on these types. Struct types define the schema of Move's [global storage](./global-storage-structure.md), and module functions define the rules for updating storage. Modules themselves are also stored in global storage. Scripts are executable entrypoints similar to a `main` function in a conventional language. A script typically calls functions of a published module that perform updates to global storage. Scripts are ephemeral code snippets that are not published in global storage. + +A Move source file (or **compilation unit**) may contain multiple modules and scripts. However, publishing a module or executing a script are separate VM operations. +# 模块和脚本 +Move 有两种不同类型的程序:模块和脚本。模块是定义结构类型以及对这些类型进行操作的函数的库。结构类型定义了 Move 的全局存储模式,模块函数定义了更新存储的规则。模块本身也存储在全局存储中。脚本是可执行的入口点,类似于传统语言中的 main 函数。脚本通常调用已发布模块的函数,这些函数执行对全局存储的更新。脚本是未在全局存储中发布的临时代码片段。 + +一个 Move 源文件(或编译单元)可能包含多个模块和脚本。但是,发布模块或执行脚本是单独的 VM 操作。 + +## Syntax + +### Scripts + +A script has the following structure: +### 脚本 +脚本具有以下结构: + +```text +script { + * + * + fun <[type parameters: constraint]*>([identifier: type]*) +} +``` + +A `script` block must start with all of its [use](./uses.md) declarations, followed by any [constants](./constants.md) and (finally) the main +[function](./functions.md) declaration. +The main function can have any name (i.e., it need not be called `main`), is the only function in a script block, can have any number of +arguments, and must not return a value. Here is an example with each of these components: + +脚本块必须以它的所有 use 声明开始,然后是任何常量和(最后)主函数声明。 main 函数可以有任何名称(即不必称为 main),是脚本块中的唯一函数,可以有任意数量的参数,并且不能返回值。以下是每个组件的示例: + +```move +script { + // Import the Debug module published at the named account address std. + use std::debug; + + const ONE: u64 = 1; + + fun main(x: u64) { + let sum = x + ONE; + debug::print(&sum) + } +} +``` + +Scripts have very limited power—they cannot declare friends, struct types or access global storage. Their primary purpose is to invoke module functions. + +脚本的功能非常有限——它们不能声明朋友、结构类型或访问全局存储。它们的主要目的是调用模块函数。 + +### Modules + +A Module has the following syntax: +### 模块 +模块具有以下语法: + +```text +module
:: { + ( | | | | )* +} +``` + +where `
` is a valid [named or literal address](./address.md). + +For example: + +其中地址是有效的命名或文字地址。 + +例如: + +```move +module 0x42::Test { + struct Example has copy, drop { i: u64 } + + use std::debug; + friend 0x42::AnotherTest; + + const ONE: u64 = 1; + + public fun print(x: u64) { + let sum = x + ONE; + let example = Example { i: sum }; + debug::print(&sum) + } +} +``` + +The `module 0x42::Test` part specifies that the module `Test` will be published under the [account address](./address.md) `0x42` in [global storage](./global-storage-structure.md). + +Modules can also be declared using [named addresses](./address.md). For example: + +模块 0x42::Test 部分指定模块 Test 将发布在全局存储中的账户地址 0x42 下。 + +模块也可以使用命名地址来声明。例如: + +```move +module test_addr::test { + struct Example has copy, drop { a: address} + + use std::debug; + friend test_addr::another_test; + + public fun print() { + let example = Example { a: @test_addr}; + debug::print(&example) + } +} +``` + +Because named addresses only exist at the source language level and during compilation, +named addresses will be fully substituted for their value at the bytecode +level. For example if we had the following code: + +因为命名地址只存在于源语言级别和编译期间,所以命名地址将在字节码级别完全替换它们的值。例如,如果我们有以下代码: + +```move= +script { + fun example() { + my_addr::m::foo(@my_addr); + } +} +``` + +and we compiled it with `my_addr` set to `0xC0FFEE`, then it would be equivalent +to the following operationally: + +我们在 my_addr 设置为 0xC0FFEE 的情况下编译它,那么它在操作上等同于以下内容: + +```move= +script { + fun example() { + 0xC0FFEE::m::foo(@0xC0FFEE); + } +} +``` + +However at the source level, these _are not equivalent_—the function +`M::foo` _must_ be accessed through the `MyAddr` named address, and not through +the numerical value assigned to that address. + +Module names can start with letters `a` to `z` or letters `A` to `Z`. After the first character, module names can contain underscores `_`, letters `a` to `z`, letters `A` to `Z`, or digits `0` to `9`. + +然而,在源代码级别,这些是不等价的——函数 M::foo 必须通过 MyAddr 命名地址访问,而不是通过分配给该地址的数值。 + +模块名称可以以字母 a 到 z 或字母 A 到 Z 开头。在第一个字符之后,模块名称可以包含下划线 `_`、字母 a 到 z、字母 A 到 Z 或数字 0 到 9。 + +```move +module my_module {} +module foo_bar_42 {} +``` + +Typically, module names start with an uppercase letter. A module named `my_module` should be stored in a source file named `my_module.move`. + +All elements inside a `module` block can appear in any order. +Fundamentally, a module is a collection of [`types`](./structs-and-resources.md) and [`functions`](./functions.md). +[Uses](./uses.md) import types from other modules. +[Friends](./friends.md) specify a list of trusted modules. +[Constants](./constants.md) define private constants that can be used in the functions of a module. + +通常,模块名称以大写字母开头。名为 my_module 的模块应存储在名为 my_module.move 的源文件中。 + +模块块内的所有元素都可以按任意顺序出现。从根本上说,模块是类型和函数的集合。使用来自其他模块的导入类型。朋友指定受信任模块的列表。常量定义了可以在模块的函数中使用的私有常量。 diff --git a/language/documentation/book/translations/move-book-zh/src/overview.md b/language/documentation/book/translations/move-book-zh/src/overview.md new file mode 100644 index 0000000000..d08bf43529 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/overview.md @@ -0,0 +1,200 @@ +--- +id: overview +title: Overview +sidebar_label: Move +--- + +Move is a next generation language for secure, sandboxed, and formally verified programming. Its first use case is for the Diem blockchain, where Move provides the foundation for its implementation. However, Move has been developed with use cases in mind outside a blockchain context as well. + +### Start Here + + + + + + + +### Primitive Types + + + + + + + + + + + +### Basic Concepts + + + + + + + + + + + + + + +### Global Storage + + + + + + +### Reference + + + + + diff --git a/language/documentation/book/translations/move-book-zh/src/packages.md b/language/documentation/book/translations/move-book-zh/src/packages.md new file mode 100644 index 0000000000..7d97bc5f63 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/packages.md @@ -0,0 +1,361 @@ +# Packages + +Packages allow Move programmers to more easily re-use code and share it +across projects. The Move package system allows programmers to easily: +* Define a package containing Move code; +* Parameterize a package by [named addresses](./address.md); +* Import and use packages in other Move code and instantiate named addresses; +* Build packages and generate associated compilation artifacts from packages; and +* Work with a common interface around compiled Move artifacts. +# 包 + +包允许 Move 程序员更轻松地重用代码并在项目之间共享。 Move 包系统允许程序员轻松地: + +* 定义一个包含移动代码的包; +* 通过命名地址参数化包; +* 在其他 Move 代码中导入和使用包并实例化命名地址; +* 构建包并从包中生成相关的编译工件;和 +* 使用围绕已编译 Move 工件的通用接口。 + +## Package Layout and Manifest Syntax + +A Move package source directory contains a `Move.toml` package manifest +file along with a set of subdirectories: +## 包布局和清单语法 +Move 包源目录包含一个 Move.toml 包清单文件以及一组子目录: + +``` +a_move_package +├── Move.toml (required) +├── sources (required) +├── examples (optional, test & dev mode) +├── scripts (optional) +├── doc_templates (optional) +└── tests (optional, test mode) +``` + +The directories marked `required` _must_ be present in order for the directory +to be considered a Move package and to be compiled. Optional directories can +be present, and if so will be included in the compilation process. Depending on +the mode that the package is built with (`test` or `dev`), the `tests` and +`examples` directories will be included as well. + +The `sources` directory can contain both Move modules and Move scripts (both +transaction scripts and modules containing script functions). The `examples` +directory can hold additional code to be used only for development and/or +tutorial purposes that will not be included when compiled outside `test` or +`dev` mode. + +A `scripts` directory is supported so transaction scripts can be separated +from modules if that is desired by the package author. The `scripts` +directory will always be included for compilation if it is present. +Documentation will be built using any documentation templates present in +the `doc_templates` directory. + +必须存在标记为必需的目录才能将该目录视为 Move 包并进行编译。可以存在可选目录,如果存在,将包含在编译过程中。根据构建包的模式(测试或开发),测试和示例目录也将包括在内。 + +源目录可以包含移动模块和移动脚本(事务脚本和包含脚本函数的模块)。示例目录可以包含仅用于开发和/或教程目的的附加代码,这些代码在测试或开发模式之外编译时不会包含在内。 + +支持脚本目录,因此如果包作者需要,可以将事务脚本与模块分开。如果存在脚本目录,则将始终包含它以进行编译。将使用 doc_templates 目录中存在的任何文档模板构建文档。 + +### Move.toml + +The Move package manifest is defined within the `Move.toml` file and has the +following syntax. Optional fields are marked with `*`, `+` denotes +one or more elements: + +Move 包清单在 Move.toml 文件中定义,并具有以下语法。可选字段标有 `*`,`+` 表示一个或多个元素: + +``` +[package] +name = # e.g., "MoveStdlib" +version = ".." # e.g., "0.1.1" +license* = # e.g., "MIT", "GPL", "Apache 2.0" +authors* = [] # e.g., ["Joe Smith (joesmith@noemail.com)", "Jane Smith (janesmith@noemail.com)"] + +[addresses] # (Optional section) Declares named addresses in this package and instantiates named addresses in the package graph +# One or more lines declaring named addresses in the following format + = "_" | "" # e.g., std = "_" or my_addr = "0xC0FFEECAFE" + +[dependencies] # (Optional section) Paths to dependencies and instantiations or renamings of named addresses from each dependency +# One or more lines declaring dependencies in the following format + = { local = , addr_subst* = { ( = ( | ""))+ } } # local dependencies + = { git = , subdir=, rev=, addr_subst* = { ( = ( | ""))+ } } # git dependencies + +[dev-addresses] # (Optional section) Same as [addresses] section, but only included in "dev" and "test" modes +# One or more lines declaring dev named addresses in the following format + = "_" | "" # e.g., std = "_" or my_addr = "0xC0FFEECAFE" + +[dev-dependencies] # (Optional section) Same as [dependencies] section, but only included in "dev" and "test" modes +# One or more lines declaring dev dependencies in the following format + = { local = , addr_subst* = { ( = ( |
))+ } } +``` + +An example of a minimal package manifest with one local dependency and one git dependency: + +具有一个本地依赖项和一个 git 依赖项的最小包清单示例: + +``` +[package] +name = "AName" +version = "0.0.0" +``` + +An example of a more standard package manifest that also includes the Move +standard library and instantiates the named address `Std` from it with the +address value `0x1`: + +一个更标准的包清单示例,它还包括 Move 标准库,并使用地址值 0x1 从中实例化命名地址 Std: + +``` +[package] +name = "AName" +version = "0.0.0" +license = "Apache 2.0" + +[addresses] +address_to_be_filled_in = "_" +specified_address = "0xB0B" + +[dependencies] +# Local dependency +LocalDep = { local = "projects/move-awesomeness", addr_subst = { "std" = "0x1" } } +# Git dependency +MoveStdlib = { git = "https://github.com/diem/diem.git", subdir="language/move-stdlib", rev = "56ab033cc403b489e891424a629e76f643d4fb6b" } + +[dev-addresses] # For use when developing this module +address_to_be_filled_in = "0x101010101" +``` + +Most of the sections in the package manifest are self explanatory, but named +addresses can be a bit difficult to understand so it's worth examining them in +a bit more detail. + +包清单中的大多数部分都是不言自明的,但命名地址可能有点难以理解,因此值得更详细地检查它们。 + +## Named Addresses During Compilation + +Recall that Move has [named addresses](./address.md) and that +named addresses cannot be declared in Move. Because of this, until now +named addresses and their values needed to be passed to the compiler on the +command line. With the Move package system this is no longer needed, and +you can declare named addresses in the package, instantiate other named +addresses in scope, and rename named addresses from other packages within +the Move package system manifest file. Let's go through each of these +individually: +## 编译期间的命名地址 +回想一下,Move 具有命名地址,并且不能在 Move 中声明命名地址。因此,到目前为止,命名地址及其值都需要在命令行上传递给编译器。使用 Move 包系统,这不再需要,您可以在包中声明命名地址,实例化范围内的其他命名地址,并从 Move 包系统清单文件中的其他包重命名命名地址。让我们分别来看看这些: + +### Declaration + +Let's say we have a Move module in `example_pkg/sources/A.move` as follows: + +### 声明 + +假设我们在 example_pkg/sources/A.move 中有一个 Move 模块,如下所示: + +```move +module named_addr::A { + public fun x(): address { @named_addr } +} +``` + +We could in `example_pkg/Move.toml` declare the named address `named_addr` in +two different ways. The first: + +我们可以在 example_pkg/Move.toml 中以两种不同的方式声明命名地址 named_addr。首先: + +``` +[package] +name = "ExamplePkg" +... +[addresses] +named_addr = "_" +``` + +Declares `named_addr` as a named address in the package `ExamplePkg` and +that _this address can be any valid address value_. Therefore an importing +package can pick the value of the named address `named_addr` to be any address +it wishes. Intuitively you can think of this as parameterizing the package +`ExamplePkg` by the named address `named_addr`, and the package can then be +instantiated later on by an importing package. + +`named_addr` can also be declared as: + +将 named_addr 声明为包 ExamplePkg 中的命名地址,并且该地址可以是任何有效的地址值。因此,导入包可以选择命名地址 named_addr 的值作为它希望的任何地址。直观地,您可以将其视为通过命名地址named_addr参数化包ExamplePkg,然后可以稍后通过导入包来实例化该包。 + +named_addr 也可以声明为: + +``` +[package] +name = "ExamplePkg" +... +[addresses] +named_addr = "0xCAFE" +``` + +which states that the named address `named_addr` is exactly `0xCAFE` and cannot be +changed. This is useful so other importing packages can use this named +address without needing to worry about the exact value assigned to it. + +With these two different declaration methods, there are two ways that +information about named addresses can flow in the package graph: +* The former ("unassigned named addresses") allows named address values to flow + from the importation site to the declaration site. +* The latter ("assigned named addresses") allows named address values to flow + from the declaration site upwards in the package graph to usage sites. + +With these two methods for flowing named address information throughout the +package graph the rules around scoping and renaming become important to +understand. + +其中指出命名地址 named_addr 正好是 0xCAFE 并且不能更改。这很有用,因此其他导入包可以使用这个命名地址,而无需担心分配给它的确切值。 + +使用这两种不同的声明方法,有关命名地址的信息可以通过两种方式在包图中流动: + +* 前者(“未分配的命名地址”)允许命名地址值从进口站点流向申报站点。 +* 后者(“分配的命名地址”)允许命名地址值从包图中的声明站点向上流动到使用站点。 + +通过这两种在整个包图中流动命名地址信息的方法,了解范围和重命名的规则变得很重要。 + +## Scoping and Renaming of Named Addresses + +A named address `N` in a package `P` is in scope if: +1. It declares a named address `N`; or +2. A package in one of `P`'s transitive dependencies declares the named address + `N` and there is a dependency path in the package graph between between `P` and the + declaring package of `N` with no renaming of `N`. + +Additionally, every named address in a package is exported. Because of this and +the above scoping rules each package can be viewed as coming with a set of +named addresses that will be brought into scope when the package is imported, +e.g., if the `ExamplePkg` package was imported, that importation would bring +into scope the `named_addr` named address. Because of this, if `P` imports two +packages `P1` and `P2` both of which declare a named address `N` an issue +arises in `P`: which "`N`" is meant when `N` is referred to in `P`? The one +from `P1` or `P2`? To prevent this ambiguity around which package a named +address is coming from, we enforce that the sets of scopes introduced by all +dependencies in a package are disjoint, and provide a way to _rename named +addresses_ when the package that brings them into scope is imported. + +Renaming a named address when importing can be done as follows in our `P`, +`P1`, and `P2` example above: +## 命名地址的范围和重命名 +包 P 中的命名地址 N 在范围内,如果: + +1. 它声明了一个命名地址N;或者 +2. P 的传递依赖项之一中的包声明了命名地址 N,并且在 P 和声明 N 的包之间的包图中存在一条依赖路径,没有重命名 N。 + +此外,包中的每个命名地址都会被导出。由于这个和上述范围规则,每个包都可以被视为带有一组命名地址,这些地址将在导入包时被纳入范围,例如,如果导入了 ExamplePkg 包,则该导入会将 named_addr 纳入范围命名地址。正因为如此,如果 P 导入两个包 P1 和 P2,这两个包都声明了一个命名地址 N,那么 P 中就会出现问题:当 P 中引用 N 时,哪个“N”是指? P1还是P2的那个?为了防止命名地址来自哪个包的这种歧义,我们强制一个包中所有依赖项引入的范围集是不相交的,并提供一种在将命名地址带入范围的包被导入时重命名命名地址的方法。 + +在我们上面的 P、P1 和 P2 示例中,可以在导入时重命名命名地址,如下所示: + +``` +[package] +name = "P" +... +[dependencies] +P1 = { local = "some_path_to_P1", addr_subst = { "P1N" = "N" } } +P2 = { local = "some_path_to_P2" } +``` + +With this renaming `N` refers to the `N` from `P2` and `P1N` will refer to `N` +coming from `P1`: + +通过这个重命名,N 指的是来自 P2 的 N,而 P1N 将指的是来自 P1 的 N: + +``` +module N::A { + public fun x(): address { @P1N } +} +``` + +It is important to note that _renaming is not local_: once a named address `N` +has been renamed to `N2` in a package `P` all packages that import `P` will not +see `N` but only `N2` unless `N` is reintroduced from outside of `P`. This is +why rule (2) in the scoping rules at the start of this section specifies a +"dependency path in the package graph between between `P` and the declaring +package of `N` with no renaming of `N`." + +重要的是要注意重命名不是本地的:一旦在包 P 中将命名地址 N 重命名为 N2,所有导入 P 的包都不会看到 N,而只会看到 N2,除非从 P 外部重新引入 N。这就是为什么规则(2) 在本节开头的作用域规则中指定了“包图中 P 和 N 的声明包之间的依赖路径,没有重命名 N。” + +### Instantiation + +Named addresses can be instantiated multiple times across the package graph as +long as it is always with the same value. It is an error if the same named +address (regardless of renaming) is instantiated with differing values across +the package graph. + +A Move package can only be compiled if all named addresses resolve to a value. +This presents issues if the package wishes to expose an uninstantiated named +address. This is what the `[dev-addresses]` section solves. This section can +set values for named addresses, but cannot introduce any named addresses. +Additionally, only the `[dev-addresses]` in the root package are included in +`dev` mode. For example a root package with the following manifest would not compile +outside of `dev` mode since `named_addr` would be uninstantiated: +### 实例化 +只要命名地址始终具有相同的值,就可以在包图中多次实例化命名地址。如果在整个包图中使用不同的值实例化相同的命名地址(无论是否重命名),则会出现错误。 + +只有当所有命名地址都解析为一个值时,才能编译 Move 包。如果包希望公开未实例化的命名地址,则会出现问题。这就是 [dev-addresses] 部分解决的问题。本节可以设置命名地址的值,但不能引入任何命名地址。此外,只有根包中的 [dev-addresses] 包含在开发模式中。例如,具有以下清单的根包不会在开发模式之外编译,因为 named_addr 将未实例化: + +``` +[package] +name = "ExamplePkg" +... +[addresses] +named_addr = "_" + +[dev-addresses] +named_addr = "0xC0FFEE" +``` + +## Usage, Artifacts, and Data Structures + +The Move package system comes with a command line option as part of the Move +CLI `move `. Unless a +particular path is provided, all package commands will run in the current working +directory. The full list of commands and flags for the Move CLI can be found by +running `move --help`. +## 用法、工件和数据结构 +Move 包系统附带一个命令行选项,作为 Move CLI 移动标志命令 command_flags 的一部分。除非提供特定路径,否则所有包命令都将在当前工作目录中运行。可以通过运行 move --help 找到 Move CLI 的命令和标志的完整列表。 + +### Usage + +A package can be compiled either through the Move CLI commands, or as a library +command in Rust with the function `compile_package`. This will create a +`CompiledPackage` that holds the compiled bytecode along with other compilation +artifacts (source maps, documentation, ABIs) in memory. This `CompiledPackage` +can be converted to an `OnDiskPackage` and vice versa -- the latter being the data of +the `CompiledPackage` laid out in the file system in the following format: +### 用法 +可以通过 Move CLI 命令编译包,也可以使用函数 compile_package 在 Rust 中编译为库命令。这将创建一个 CompiledPackage,它在内存中保存已编译的字节码以及其他编译工件(源映射、文档、ABI)。这个 CompiledPackage 可以转换为 OnDiskPackage ,反之亦然 - 后者是 CompiledPackage 的数据,以下列格式在文件系统中布局: + +``` +a_move_package +├── Move.toml +... +└── build + ├── + │   ├── BuildInfo.yaml + │   ├── bytecode_modules + │   │   └── *.mv + │   ├── source_maps + │   │   └── *.mvsm + │ ├── bytecode_scripts + │ │   └── *.mv + │ ├── abis + │ │   ├── *.abi + │ │   └── /*.abi + │   └── sources + │   └── *.move + ... + └── + ├── BuildInfo.yaml + ... + └── sources +``` + +See the `move-package` crate for more information on these data structures and +how to use the Move package system as a Rust library. + +有关这些数据结构以及如何将 Move 包系统用作 Rust 库的更多信息,请参阅 move-package crate。 diff --git a/language/documentation/book/translations/move-book-zh/src/references.md b/language/documentation/book/translations/move-book-zh/src/references.md new file mode 100644 index 0000000000..72762491cb --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/references.md @@ -0,0 +1,277 @@ +# References + +Move has two types of references: immutable `&` and mutable `&mut`. Immutable references are read +only, and cannot modify the underlying value (or any of its fields). Mutable references allow for +modifications via a write through that reference. Move's type system enforces an ownership +discipline that prevents reference errors. + +For more details on the rules of references, see [Structs and Resources](./structs-and-resources.md) +# 参考 +Move 有两种类型的引用:不可变的 & 和可变的 &mut。不可变引用是只读的,不能修改基础值(或其任何字段)。可变引用允许通过写入该引用进行修改。 Move 的类型系统强制执行防止引用错误的所有权规则。 + +有关引用规则的更多详细信息,请参阅结构和资源 + +## Reference Operators + +Move provides operators for creating and extending references as well as converting a mutable +reference to an immutable one. Here and elsewhere, we use the notation `e: T` for "expression `e` +has type `T`". +## 引用运算符 +Move 提供了用于创建和扩展引用以及将可变引用转换为不可变引用的运算符。在这里和其他地方,我们使用符号 e: T 来表示“表达式 e 具有类型 T”。 + +| Syntax | Type | Description | +| ----------- | ----------------------------------------------------- | -------------------------------------------------------------- | +| `&e` | `&T` where `e: T` and `T` is a non-reference type | Create an immutable reference to `e` | +| `&mut e` | `&mut T` where `e: T` and `T` is a non-reference type | Create a mutable reference to `e`. | +| `&e.f` | `&T` where `e.f: T` | Create an immutable reference to field `f` of struct `e`. | +| `&mut e.f` | `&mut T` where `e.f: T` | Create a mutable reference to field `f` of struct`e`. | +| `freeze(e)` | `&T` where `e: &mut T` | Convert the mutable reference `e` into an immutable reference. | + +The `&e.f` and `&mut e.f` operators can be used both to create a new reference into a struct or to +extend an existing reference: + +&e.f 和 &mut e.f 运算符既可用于创建对结构的新引用,也可用于扩展现有引用: + +```move +let s = S { f: 10 }; +let f_ref1: &u64 = &s.f; // works +let s_ref: &S = &s; +let f_ref2: &u64 = &s_ref.f // also works +``` + +A reference expression with multiple fields works as long as both structs are in the same module: + +只要两个结构都在同一个模块中,具有多个字段的引用表达式就可以工作: + +```move +struct A { b: B } +struct B { c : u64 } +fun f(a: &A): &u64 { + &a.b.c +} +``` + +Finally, note that references to references are not allowed: + +最后,请注意,不允许引用引用: + +```move +let x = 7; +let y: &u64 = &x; +let z: &&u64 = &y; // will not compile +``` + +## Reading and Writing Through References + +Both mutable and immutable references can be read to produce a copy of the referenced value. + +Only mutable references can be written. A write `*x = v` discards the value previously stored in `x` +and updates it with `v`. + +Both operations use the C-like `*` syntax. However, note that a read is an expression, whereas a +write is a mutation that must occur on the left hand side of an equals. + +## 通过参考文献阅读和写作 +可以读取可变和不可变引用以生成引用值的副本。 + +只能编写可变引用。写入 `*x = v` 会丢弃先前存储在 x 中的值并用 v 更新它。 + +这两个操作都使用类 C 的 `*` 语法。但是,请注意,读是一个表达式,而写是一个突变,必须发生在等号的左侧。 + +| Syntax | Type | Description | +| ---------- | ----------------------------------- | ----------------------------------- | +| `*e` | `T` where `e` is `&T` or `&mut T` | Read the value pointed to by `e` | +| `*e1 = e2` | `()` where `e1: &mut T` and `e2: T` | Update the value in `e1` with `e2`. | + +In order for a reference to be read, the underlying type must have the +[`copy` ability](./abilities.md) as reading the reference creates a new copy of the value. This rule +prevents the copying of resource values: + +为了读取引用,基础类型必须具有复制能力,因为读取引用会创建值的新副本。此规则防止复制资源值: + +```move= +fun copy_resource_via_ref_bad(c: Coin) { + let c_ref = &c; + let counterfeit: Coin = *c_ref; // not allowed! + pay(c); + pay(counterfeit); +} +``` + +Dually: in order for a reference to be written to, the underlying type must have the +[`drop` ability](./abilities.md) as writing to the reference will discard (or "drop") the old value. +This rule prevents the destruction of resource values: +双重:为了写入引用,基础类型必须具有删除能力,因为写入引用将丢弃(或“删除”)旧值。此规则可防止破坏资源值: + +```move= +fun destroy_resource_via_ref_bad(ten_coins: Coin, c: Coin) { + let ref = &mut ten_coins; + *ref = c; // not allowed--would destroy 10 coins! +} +``` + +## `freeze` inference + +A mutable reference can be used in a context where an immutable reference is expected: +## 冻结推理 +可变引用可以在需要不可变引用的上下文中使用: + +```move +let x = 7; +let y: &mut u64 = &mut x; +``` + +This works because the under the hood, the compiler inserts `freeze` instructions where they are +needed. Here are a few more examples of `freeze` inference in action: +这是因为在底层,编译器会在需要的地方插入冻结指令。以下是冻结推理的更多示例: + +```move= +fun takes_immut_returns_immut(x: &u64): &u64 { x } + +// freeze inference on return value +fun takes_mut_returns_immut(x: &mut u64): &u64 { x } + +fun expression_examples() { + let x = 0; + let y = 0; + takes_immut_returns_immut(&x); // no inference + takes_immut_returns_immut(&mut x); // inferred freeze(&mut x) + takes_mut_returns_immut(&mut x); // no inference + + assert!(&x == &mut y, 42); // inferred freeze(&mut y) +} + +fun assignment_examples() { + let x = 0; + let y = 0; + let imm_ref: &u64 = &x; + + imm_ref = &x; // no inference + imm_ref = &mut y; // inferred freeze(&mut y) +} +``` + +### Subtyping + +With this `freeze` inference, the Move type checker can view `&mut T` as a subtype of `&T`. As shown +above, this means that anywhere for any expression where a `&T` value is used, a `&mut T` value can +also be used. This terminology is used in error messages to concisely indicate that a `&mut T` was +needed where a `&T` was supplied. For example +### 子类型化 +通过这种冻结推断,Move 类型检查器可以将 &mut T 视为 &T 的子类型。如上所示,这意味着对于任何使用 &T 值的表达式,也可以使用 &mut T 值。此术语用于错误消息中,以简明扼要地表明在提供 &T 的情况下需要 &mut T。例如 + +```move= +address 0x42 { +module example { + fun read_and_assign(store: &mut u64, new_value: &u64) { + *store = *new_value + } + + fun subtype_examples() { + let x: &u64 = &0; + let y: &mut u64 = &mut 1; + + x = &mut 1; // valid + y = &2; // invalid! + + read_and_assign(y, x); // valid + read_and_assign(x, y); // invalid! + } +} +} +``` + +will yield the following error messages +将产生以下错误消息 + +```text +error: + + ┌── example.move:12:9 ─── + │ + 12 │ y = &2; // invalid! + │ ^ Invalid assignment to local 'y' + · + 12 │ y = &2; // invalid! + │ -- The type: '&{integer}' + · + 9 │ let y: &mut u64 = &mut 1; + │ -------- Is not a subtype of: '&mut u64' + │ + +error: + + ┌── example.move:15:9 ─── + │ + 15 │ read_and_assign(x, y); // invalid! + │ ^^^^^^^^^^^^^^^^^^^^^ Invalid call of '0x42::example::read_and_assign'. Invalid argument for parameter 'store' + · + 8 │ let x: &u64 = &0; + │ ---- The type: '&u64' + · + 3 │ fun read_and_assign(store: &mut u64, new_value: &u64) { + │ -------- Is not a subtype of: '&mut u64' + │ +``` + +The only other types currently that has subtyping are [tuples](./tuples.md) + +当前唯一具有子类型的其他类型是元组 + +## Ownership + +Both mutable and immutable references can always be copied and extended _even if there are existing +copies or extensions of the same reference_: +## 所有权 +即使存在相同引用的现有副本或扩展,可变引用和不可变引用也始终可以被复制和扩展: + +```move +fun reference_copies(s: &mut S) { + let s_copy1 = s; // ok + let s_extension = &mut s.f; // also ok + let s_copy2 = s; // still ok + ... +} +``` + +This might be surprising for programmers familiar with Rust's ownership system, which would reject +the code above. Move's type system is more permissive in its treatment of +[copies](./variables.md#move-and-copy), but equally strict in ensuring unique ownership of mutable +references before writes. + +对于熟悉 Rust 所有权系统的程序员来说,这可能会令人惊讶,因为他们会拒绝上面的代码。 Move 的类型系统在处理副本方面更加宽松,但在写入前确保可变引用的唯一所有权方面同样严格。 + +### References Cannot Be Stored + +References and tuples are the _only_ types that cannot be stored as a field value of structs, which +also means that they cannot exist in global storage. All references created during program execution +will be destroyed when a Move program terminates; they are entirely ephemeral. This invariant is +also true for values of types without the `store` [ability](./abilities.md), but note that +references and tuples go a step further by never being allowed in structs in the first place. + +This is another difference between Move and Rust, which allows references to be stored inside of +structs. + +Currently, Move cannot support this because references cannot be +[serialized](https://en.wikipedia.org/wiki/Serialization), but _every Move value must be +serializable_. This requirement comes from Move's +[persistent global storage](./global-storage-structure.md), which needs to serialize values to +persist them across program executions. Structs can be written to global storage, and thus they must +be serializable. + +One could imagine a fancier, more expressive, type system that would allow references to be stored +in structs _and_ ban those structs from existing in global storage. We could perhaps allow +references inside of structs that do not have the `store` [ability](./abilities.md), but that would +not completely solve the problem: Move has a fairly complex system for tracking static reference +safety, and this aspect of the type system would also have to be extended to support storing +references inside of structs. In short, Move's type system (particularly the aspects around +reference safety) would have to expand to support stored references. But it is something we are +keeping an eye on as the language evolves. +### 无法存储引用 +引用和元组是唯一不能存储为结构的字段值的类型,这也意味着它们不能存在于全局存储中。当 Move 程序终止时,程序执行期间创建的所有引用都将被销毁;它们完全是短暂的。这个不变量对于没有存储能力的类型的值也是正确的,但请注意,引用和元组更进一步,因为从一开始就不允许在结构中。 + +这是 Move 和 Rust 之间的另一个区别,后者允许将引用存储在结构内。 + +目前,Move 无法支持这一点,因为引用无法序列化,但每个 Move 值都必须是可序列化的。这个需求来自于 Move 的持久化全局存储,它需要序列化值以在程序执行中持久化它们。结构可以写入全局存储,因此它们必须是可序列化的。 + +可以想象一种更奇特、更有表现力的类型系统,它允许将引用存储在结构中,并禁止这些结构存在于全局存储中。我们也许可以允许不具备存储能力的结构内部的引用,但这并不能完全解决问题:Move 有一个相当复杂的系统来跟踪静态引用安全,并且类型系统的这方面也必须扩展支持在结构内存储引用。简而言之,Move 的类型系统(尤其是与引用安全相关的方面)必须扩展以支持存储的引用。但随着语言的发展,我们一直在关注这一点。 diff --git a/language/documentation/book/translations/move-book-zh/src/signer.md b/language/documentation/book/translations/move-book-zh/src/signer.md new file mode 100644 index 0000000000..47d16fc707 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/signer.md @@ -0,0 +1,93 @@ +# Signer + +`signer` is a built-in Move resource type. A `signer` is a +[capability](https://en.wikipedia.org/wiki/Object-capability_model) that allows the holder to act on +behalf of a particular `address`. You can think of the native implementation as being: +# 签名者 +signer 是内置的 Move 资源类型。签名者是一种允许持有者代表特定地址行事的能力。您可以将本机实现视为: + +struct signer 有 drop { a: address } +签名者有点类似于 Unix UID,因为它表示通过 Move 之外的代码(例如,通过检查加密签名或密码)进行身份验证的用户。 + +```move +struct signer has drop { a: address } +``` + +A `signer` is somewhat similar to a Unix [UID](https://en.wikipedia.org/wiki/User_identifier) in +that it represents a user authenticated by code _outside_ of Move (e.g., by checking a cryptographic +signature or password). +签名者有点类似于 Unix UID,因为它表示通过 Move 之外的代码(例如,通过检查加密签名或密码)进行身份验证的用户。 + +## Comparison to `address` + +A Move program can create any `address` value without special permission using address literals: +## 比较地址 +Move 程序可以使用地址文字创建任何地址值,而无需特殊许可: + +```move +let a1 = @0x1; +let a2 = @0x2; +// ... and so on for every other possible address +``` + +However, `signer` values are special because they cannot be created via literals or +instructions--only by the Move VM. Before the VM runs a script with parameters of type `signer`, it +will automatically create `signer` values and pass them into the script: + +但是,签名者值是特殊的,因为它们不能通过文字或指令创建,只能由 Move VM 创建。在虚拟机运行带有签名者类型参数的脚本之前,它会自动创建签名者值并将它们传递给脚本: + +```move= +script { + use std::signer; + fun main(s: signer) { + assert!(signer::address_of(&s) == @0x42, 0); + } +} +``` + +This script will abort with code `0` if the script is sent from any address other than `0x42`. + +A transaction script can have an arbitrary number of `signer`s as long as the signers are a prefix +to any other arguments. In other words, all of the signer arguments must come first: +如果脚本是从 0x42 以外的任何地址发送的,则此脚本将以代码 0 中止。 + +只要签名者是任何其他参数的前缀,事务脚本就可以有任意数量的签名者。换句话说,所有的签名者参数都必须放在第一位: + +```move= +script { + use std::signer; + fun main(s1: signer, s2: signer, x: u64, y: u8) { + // ... + } +} +``` + +This is useful for implementing _multi-signer scripts_ that atomically act with the authority of +multiple parties. For example, an extension of the script above could perform an atomic currency +swap between `s1` and `s2`. +这对于实现具有多方权限的原子行为的多签名者脚本很有用。例如,上述脚本的扩展可以在 s1 和 s2 之间执行原子货币交换。 + +## `signer` Operators + +The `std::signer` standard library module provides two utility functions over `signer` values: +## 签名者运算符 +std::signer 标准库模块为签名者值提供了两个实用函数: + +| Function | Description | +| ------------------------------------------- | ------------------------------------------------------------- | +| `signer::address_of(&signer): address` | Return the `address` wrapped by this `&signer`. | +| `signer::borrow_address(&signer): &address` | Return a reference to the `address` wrapped by this `&signer` | + +In addition, the `move_to(&signer, T)` [global storage operator](./global-storage-operators.md) +requires a `&signer` argument to publish a resource `T` under `signer.address`'s account. This +ensures that only an authenticated user can elect to publish a resource under their `address`. + +此外,move_to T (&signer, T) 全局存储操作符需要一个 &signer 参数来在 signer.address 的帐户下发布资源 T。这确保了只有经过身份验证的用户才能选择在其地址下发布资源。 + +## Ownership + +Unlike simple scalar values, `signer` values are not copyable, meaning they cannot be copied (from +any operation whether it be through an explicit [`copy`](./variables.md#move-and-copy) instruction +or through a [dereference `*`](./references.md#reference-operators)). +## 所有权 +与简单的标量值不同,签名者值是不可复制的,这意味着它们不能被复制(通过任何操作,无论是通过显式复制指令还是通过取消引用 *)。 diff --git a/language/documentation/book/translations/move-book-zh/src/standard-library.md b/language/documentation/book/translations/move-book-zh/src/standard-library.md new file mode 100644 index 0000000000..4609449b46 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/standard-library.md @@ -0,0 +1,702 @@ +# Standard Library + +The Move standard library exposes interfaces that implement the following functionality: +* [Basic operations on vectors](#vector). +* [Option types and operations on`Option` types](#option). +* [A common error encoding code interface for abort codes](#errors). +* [32-bit precision fixed-point numbers](#fixed_point32). + +# 标准库 +Move 标准库公开了实现以下功能的接口: + +* 向量的基本操作。 +* 选项类型和选项类型的操作。 +* 中止代码的常见错误编码代码接口。 +* 32 位精度定点数。 + +## vector + +The `vector` module defines a number of operations over the primitive +[`vector`](./vector.md) type. The module is published under the +named address `Std` and consists of a number of native functions, as +well as functions defined in Move. The API for this module is as follows. + +## 向量 +vector 模块定义了对原始向量类型的许多操作。该模块在命名地址 Std 下发布,由许多本机函数以及 Move 中定义的函数组成。该模块的 API 如下。 + +### Functions +### 函数 + +--------------------------------------------------------------------------- + +Create an empty [`vector`](./vector.md). +The `Element` type can be both a `resource` or `copyable` type. + +创建一个空向量。 Element 类型既可以是资源类型,也可以是可复制类型。 + +```move + native public fun empty(): vector; +``` + +--------------------------------------------------------------------------- + +Create a vector of length `1` containing the passed in `element`. + +创建一个包含传入元素的长度为 1 的向量。 + +```move + public fun singleton(e: Element): vector; +``` + +--------------------------------------------------------------------------- + +Destroy (deallocate) the vector `v`. Will abort if `v` is non-empty. +*Note*: The emptiness restriction is due to the fact that `Element` can be a +resource type, and destruction of a non-empty vector would violate +[resource conservation](./structs-and-resources.md). + +销毁(解除分配)向量 v。如果 v 不为空,将中止。注意:空性限制是由于 Element 可以是资源类型,销毁非空向量会违反资源守恒。 + +```move + native public fun destroy_empty(v: vector); +``` + +--------------------------------------------------------------------------- + +Acquire an [immutable reference](./references.md) to the `i`th element of the vector `v`. Will abort if +the index `i` is out of bounds for the vector `v`. + +获取对向量 v 的第 i 个元素的不可变引用。如果索引 i 超出向量 v 的范围,将中止。 + +```move + native public fun borrow(v: &vector, i: u64): ∈ +``` + +--------------------------------------------------------------------------- + +Acquire a [mutable reference](./references.md) +to the `i`th element of the vector `v`. Will abort if +the index `i` is out of bounds for the vector `v`. + +获取对向量 v 的第 i 个元素的可变引用。如果索引 i 超出向量 v 的范围,将中止。 + +```move + native public fun borrow_mut(v: &mut vector, i: u64): &mut Element; +``` + +--------------------------------------------------------------------------- + +Empty and destroy the `other` vector, and push each of the elements in +the `other` vector onto the `lhs` vector in the same order as they occurred in `other`. + +清空并销毁另一个向量,并将另一个向量中的每个元素以与它们在其他向量中出现的顺序相同的顺序推送到 lhs 向量上。 + +```move + public fun append(lhs: &mut vector, other: vector); +``` + +--------------------------------------------------------------------------- + +Push an element `e` of type `Element` onto the end of the vector `v`. May +trigger a resizing of the underlying vector's memory. + +将 Element 类型的元素 e 推到向量 v 的末尾。可能会触发底层向量内存的大小调整。 + +```move + native public fun push_back(v: &mut vector, e: Element); +``` + +--------------------------------------------------------------------------- + +Pop an element from the end of the vector `v` in-place and return the owned +value. Will abort if `v` is empty. + +从向量 v 的末尾就地弹出一个元素并返回拥有的值。如果 v 为空,将中止。 + +```move + native public fun pop_back(v: &mut vector): Element; +``` + +--------------------------------------------------------------------------- + +Remove the element at index `i` in the vector `v` and return the owned value +that was previously stored at `i` in `v`. All elements occurring at indices +greater than `i` will be shifted down by 1. Will abort if `i` is out of bounds +for `v`. + +删除向量 v 中索引 i 处的元素,并返回先前存储在 v 中 i 处的拥有值。所有出现在索引处大于 i 的元素将向下移动 1。如果 i 超出 v 的范围,将中止。 + +```move + public fun remove(v: &mut vector, i: u64): Element; +``` + +--------------------------------------------------------------------------- + +Swap the `i`th element of the vector `v` with the last element and then pop +this element off of the back of the vector and return the owned value that +was previously stored at index `i`. +This operation is O(1), but does not preserve ordering of elements in the vector. +Aborts if the index `i` is out of bounds for the vector `v`. + +将向量 v 的第 i 个元素与最后一个元素交换,然后将该元素从向量的背面弹出,并返回之前存储在索引 i 处的拥有值。此操作为 O(1),但不保留向量中元素的顺序。如果索引 i 超出向量 v 的范围,则中止。 + +```move + public fun swap_remove(v: &mut vector, i: u64): Element; +``` + +--------------------------------------------------------------------------- + +Swap the elements at the `i`'th and `j`'th indices in the vector `v`. Will +abort if either of `i` or `j` are out of bounds for `v`. + +交换向量 v 中第 i 个和第 j 个索引处的元素。如果 i 或 j 中的任何一个超出 v 的范围,则将中止。 + +```move + native public fun swap(v: &mut vector, i: u64, j: u64); +``` + +--------------------------------------------------------------------------- + +Reverse the order of the elements in the vector `v` in-place. + +就地反转向量 v 中元素的顺序。 + +```move + public fun reverse(v: &mut vector); +``` + +--------------------------------------------------------------------------- + +Return the index of the first occurrence of an element in `v` that is +equal to `e`. Returns `(true, index)` if such an element was found, and +`(false, 0)` otherwise. + +返回 v 中等于 e 的元素第一次出现的索引。如果找到这样的元素,则返回 (true, index),否则返回 (false, 0)。 + +```move + public fun index_of(v: &vector, e: &Element): (bool, u64); +``` + +--------------------------------------------------------------------------- + +Return if an element equal to `e` exists in the vector `v`. + +如果向量 v 中存在等于 e 的元素,则返回。 + +```move + public fun contains(v: &vector, e: &Element): bool; +``` + +--------------------------------------------------------------------------- + +Return the length of a `vector`. + +返回向量的长度。 + +```move + native public fun length(v: &vector): u64; +``` + +--------------------------------------------------------------------------- + +Return whether the vector `v` is empty. + +返回向量 v 是否为空。 + +```move + public fun is_empty(v: &vector): bool; +``` + +--------------------------------------------------------------------------- + +## option + +The `option` module defines a generic option type `Option` that represents a +value of type `T` that may, or may not, be present. It is published under the named address `Std`. + +The Move option type is internally represented as a singleton vector, and may +contain a value of `resource` or `copyable` kind. If you are familiar with option +types in other languages, the Move `Option` behaves similarly to those with a +couple notable exceptions since the option can contain a value of kind `resource`. +Particularly, certain operations such as `get_with_default` and +`destroy_with_default` require that the element type `T` be of `copyable` kind. + +The API for the `option` module is as as follows + +## 选项 +选项模块定义了一个通用选项类型 Option T,它代表一个类型 T 的值,该值可能存在,也可能不存在。它以命名地址 Std 发布。 + +Move 选项类型在内部表示为单例向量,并且可能包含资源或可复制种类的值。如果您熟悉其他语言中的选项类型,则移动选项的行为类似于那些具有几个值得注意的例外的选项,因为该选项可以包含 kind 资源的值。特别是,某些操作,如 get_with_default 和 destroy_with_default 要求元素类型 T 是可复制类型。 + +选件模块的 API 如下 + +### Types + +Generic type abstraction of a value that may, or may not, be present. Can contain +a value of either `resource` or `copyable` kind. +### 类型 +可能存在或不存在的值的通用类型抽象。可以包含资源或可复制类型的值。 + +```move + struct Option; +``` + +### Functions + +Create an empty `Option` of that can contain a value of `Element` type. + +### 功能 +创建一个可以包含元素类型值的空选项。 + +```move + public fun none(): Option; +``` + +--------------------------------------------------------------------------- + +Create a non-empty `Option` type containing a value `e` of type `Element`. + +创建一个包含 Element 类型的值 e 的非空 Option 类型。 + +```move + public fun some(e: T): Option; +``` + +--------------------------------------------------------------------------- + +Return an immutable reference to the value inside the option `opt_elem` +Will abort if `opt_elem` does not contain a value. + +返回对选项 opt_elem 中值的不可变引用 如果 opt_elem 不包含值,将中止。 + +```move + public fun borrow(opt_elem: &Option): ∈ +``` + +--------------------------------------------------------------------------- + +Return a reference to the value inside `opt_elem` if it contains one. If +`opt_elem` does not contain a value the passed in `default_ref` reference will be returned. +Does not abort. + +如果它包含一个,则返回对 opt_elem 内的值的引用。如果 opt_elem 不包含值,则将返回传入的 default_ref 引用。不中止。 + +```move + public fun borrow_with_default(opt_elem: &Option, default_ref: &Element): ∈ +``` + +--------------------------------------------------------------------------- + +Return a mutable reference to the value inside `opt_elem`. Will abort if +`opt_elem` does not contain a value. + +返回对 opt_elem 中值的可变引用。如果 opt_elem 不包含值,将中止。 + +```move + public fun borrow_mut(opt_elem: &mut Option): &mut Element; +``` + +--------------------------------------------------------------------------- + +Convert an option value that contains a value to one that is empty in-place by +removing and returning the value stored inside `opt_elem`. +Will abort if `opt_elem` does not contain a value. + +通过删除并返回存储在 opt_elem 中的值,将包含值的选项值转换为就地为空的值。如果 opt_elem 不包含值,将中止。 + +```move + public fun extract(opt_elem: &mut Option): Element; +``` + +--------------------------------------------------------------------------- + +Return the value contained inside the option `opt_elem` if it contains one. +Will return the passed in `default` value if `opt_elem` does not contain a +value. The `Element` type that the `Option` type is instantiated with must be +of `copyable` kind in order for this function to be callable. + +如果它包含一个,则返回选项 opt_elem 中包含的值。如果 opt_elem 不包含值,将返回传入的默认值。用于实例化 Option 类型的 Element 类型必须是可复制类型,才能使此函数可调用。 + +```move + public fun get_with_default(opt_elem: &Option, default: Element): Element; +``` + +--------------------------------------------------------------------------- + +Convert an empty option `opt_elem` to an option value that contains the value `e`. +Will abort if `opt_elem` already contains a value. + +将空选项 opt_elem 转换为包含值 e 的选项值。如果 opt_elem 已经包含一个值,将中止。 + +```move + public fun fill(opt_elem: &mut Option, e: Element); +``` + +--------------------------------------------------------------------------- + +Swap the value currently contained in `opt_elem` with `new_elem` and return the +previously contained value. Will abort if `opt_elem` does not contain a value. + +将 opt_elem 中当前包含的值交换为 new_elem 并返回先前包含的值。如果 opt_elem 不包含值,将中止。 + +```move + public fun swap(opt_elem: &mut Option, e: Element): Element; +``` + +--------------------------------------------------------------------------- + +Return true if `opt_elem` contains a value equal to the value of `e_ref`. +Otherwise, `false` will be returned. + +如果 opt_elem 包含的值等于 e_ref 的值,则返回 true。否则,将返回 false。 + +```move + public fun contains(opt_elem: &Option, e_ref: &Element): bool; +``` + +--------------------------------------------------------------------------- + +Return `true` if `opt_elem` does not contain a value. + +如果 opt_elem 不包含值,则返回 true。 + +```move + public fun is_none(opt_elem: &Option): bool; +``` + +--------------------------------------------------------------------------- + +Return `true` if `opt_elem` contains a value. + +如果 opt_elem 包含一个值,则返回 true。 + +```move + public fun is_some(opt_elem: &Option): bool; +``` + +--------------------------------------------------------------------------- + +Unpack `opt_elem` and return the value that it contained. +Will abort if `opt_elem` does not contain a value. + +解包 opt_elem 并返回它包含的值。如果 opt_elem 不包含值,将中止。 + +```move + public fun destroy_some(opt_elem: Option): Element; +``` + +--------------------------------------------------------------------------- + +Destroys the `opt_elem` value passed in. If `opt_elem` contained a value it +will be returned otherwise, the passed in `default` value will be returned. + +销毁传入的 opt_elem 值。如果 opt_elem 包含值,则返回,否则返回传入的默认值。 + +```move + public fun destroy_with_default(opt_elem: Option, default: Element): Element; +``` + +--------------------------------------------------------------------------- + +Destroys the `opt_elem` value passed in, `opt_elem` must be empty and not +contain a value. Will abort if `opt_elem` contains a value. + +销毁传入的 opt_elem 值,opt_elem 必须为空且不包含值。如果 opt_elem 包含一个值,将中止。 + +```move + public fun destroy_none(opt_elem: Option); +``` + +## errors + +Recall that each abort code in Move is represented as an unsigned 64-bit integer. The `errors` module defines a common interface that can be used to "tag" each of these abort codes so that they can represent both the error **category** along with an error **reason**. + +Error categories are declared as constants in the `errors` module and are globally unique with respect to this module. Error reasons on the other hand are module-specific error codes, and can provide greater detail (perhaps, even a particular _reason_) about the specific error condition. This representation of a category and reason for each error code is done by dividing the abort code into two sections. + +The lower 8 bits of the abort code hold the *error category*. The remaining 56 bits of the abort code hold the *error reason*. +The reason should be a unique number relative to the module which raised the error and can be used to obtain more information about the error at hand. It should mostly be used for diagnostic purposes as error reasons may change over time if the module is updated. +## 错误 +回想一下,Move 中的每个中止代码都表示为一个无符号的 64 位整数。 errors 模块定义了一个通用接口,可用于“标记”每个中止代码,以便它们可以表示错误类别和错误原因。 + +错误类别在错误模块中被声明为常量,并且相对于该模块是全局唯一的。另一方面,错误原因是特定于模块的错误代码,可以提供有关特定错误条件的更多详细信息(甚至可能是特定原因)。每个错误代码的类别和原因的这种表示是通过将中止代码分为两部分来完成的。 + +中止代码的低 8 位保存错误类别。中止代码的剩余 56 位保存错误原因。原因应该是相对于引发错误的模块的唯一编号,并且可用于获取有关手头错误的更多信息。它应该主要用于诊断目的,因为如果更新模块,错误原因可能会随着时间而改变。 + +| Category | Reason | +|----------|--------| +| 8 bits | 56 bits| + +Since error categories are globally stable, these present the most stable API and should in general be what is used by clients to determine the messages they may present to users (whereas the reason is useful for diagnostic purposes). There are public functions in the `errors` module for creating an abort code of each error category with a specific `reason` number (represented as a `u64`). + +由于错误类别是全局稳定的,因此它们提供了最稳定的 API,通常应该是客户端用来确定它们可能呈现给用户的消息的内容(而原因对于诊断目的很有用)。错误模块中有公共函数,用于为每个错误类别创建一个带有特定原因号的中止代码(表示为 u64)。 + +### Constants + +The system is in a state where the performed operation is not allowed. + +### 常数 +系统处于不允许执行的操作的状态。 + +```move + const INVALID_STATE: u8 = 1; +``` + +--------------------------------------------------------------------------- +A specific account address was required to perform an operation, but a different address from what was expected was encounterd. + +执行操作需要特定的帐户地址,但遇到了与预期不同的地址。 + +```move + const REQUIRES_ADDRESS: u8 = 2; +``` + +--------------------------------------------------------------------------- +An account did not have the expected role for this operation. Useful for Role Based Access Control (RBAC) error conditions. + +帐户没有此操作的预期角色。对于基于角色的访问控制 (RBAC) 错误情况很有用。 + +```move + const REQUIRES_ROLE: u8 = 3; +``` + +--------------------------------------------------------------------------- +An account did not not have a required capability. Useful for RBAC error conditions. + +帐户没有所需的功能。对于 RBAC 错误情况很有用。 + +```move + const REQUIRES_CAPABILITY: u8 = 4; +``` + +--------------------------------------------------------------------------- +A resource was expected, but did not exist under an address. + +应有资源,但地址下不存在。 + +```move + const NOT_PUBLISHED: u8 = 5; +``` + +--------------------------------------------------------------------------- +Attempted to publish a resource under an address where one was already published. + +尝试在已发布资源的地址下发布资源。 + +```move + const ALREADY_PUBLISHED: u8 = 6; +``` + +--------------------------------------------------------------------------- +An argument provided for an operation was invalid. + +为操作提供的参数无效。 + +```move + const INVALID_ARGUMENT: u8 = 7; +``` + +--------------------------------------------------------------------------- +A limit on a value was exceeded. + +超出了某个值的限制。 + +```move + const LIMIT_EXCEEDED: u8 = 8; +``` + +--------------------------------------------------------------------------- +An internal error (bug) has occurred. + +发生内部错误(错误)。 + +```move + const INTERNAL: u8 = 10; +``` + +--------------------------------------------------------------------------- +A custom error category for extension points. + +扩展点的自定义错误类别。 + +```move + const CUSTOM: u8 = 255; +``` + +--------------------------------------------------------------------------- + +### Functions + + Should be used in the case where invalid (global) state is encountered. Constructs an abort code with specified `reason` and category `INVALID_STATE`. Will abort if `reason` does not fit in 56 bits. + +### 函数 + +应该在遇到无效(全局)状态的情况下使用。构造具有指定原因和类别 INVALID_STATE 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun invalid_state(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if an account's address does not match a specific address. Constructs an abort code with specified `reason` and category `REQUIRES_ADDRESS`. Will abort if `reason` does not fit in 56 bits. + +如果帐户的地址与特定地址不匹配,则应使用。构造具有指定原因和类别 REQUIRES_ADDRESS 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun requires_address(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if a role did not match a required role when using RBAC. Constructs an abort code with specified `reason` and category `REQUIRES_ROLE`. Will abort if `reason` does not fit in 56 bits. + +如果在使用 RBAC 时角色与所需角色不匹配,则应使用该角色。构造具有指定原因和类别 REQUIRES_ROLE 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun requires_role(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if an account did not have a required capability when using RBAC. Constructs an abort code with specified `reason` and category `REQUIRES_CAPABILITY`. Should be Will abort if `reason` does not fit in 56 bits. + +如果帐户在使用 RBAC 时没有所需的功能,则应使用。构造具有指定原因和类别 REQUIRES_CAPABILITY 的中止代码。如果原因不适合 56 位,则应该是将中止。 + +```move + public fun requires_capability(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if a resource did not exist where one was expected. Constructs an abort code with specified `reason` and category `NOT_PUBLISHED`. Will abort if `reason` does not fit in 56 bits. + +如果资源在预期的地方不存在,则应使用该资源。构造具有指定原因和类别 NOT_PUBLISHED 的中止代码。如果原因不适合 56 位,将中止。 + + +```move + public fun not_published(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if a resource already existed where one was about to be published. Constructs an abort code with specified `reason` and category `ALREADY_PUBLISHED`. Will abort if `reason` does not fit in 56 bits. + +如果资源已经存在且即将发布,则应使用该资源。构造一个具有指定原因和类别 ALREADY_PUBLISHED 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun already_published(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if an invalid argument was passed to a function/operation. Constructs an abort code with specified `reason` and category `INVALID_ARGUMENT`. Will abort if `reason` does not fit in 56 bits. + +如果将无效参数传递给函数/操作,则应使用。构造具有指定原因和类别 INVALID_ARGUMENT 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun invalid_argument(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if a limit on a specific value is reached, e.g., subtracting 1 from a value of 0. Constructs an abort code with specified `reason` and category `LIMIT_EXCEEDED`. Will abort if `reason` does not fit in 56 bits. + +如果达到特定值的限制,则应使用,例如,从 0 中减去 1。构造具有指定原因和类别 LIMIT_EXCEEDED 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun limit_exceeded(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Should be used if an internal error or bug was encountered. Constructs an abort code with specified `reason` and category `INTERNAL`. Will abort if `reason` does not fit in 56 bits. + +如果遇到内部错误或错误,应使用。构造具有指定原因和类别 INTERNAL 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun internal(reason: u64): u64; +``` + +--------------------------------------------------------------------------- +Used for extension points, should be not used under most circumstances. Constructs an abort code with specified `reason` and category `CUSTOM`. Will abort if `reason` does not fit in 56 bits. + +用于扩展点,在大多数情况下不应该使用。构造具有指定原因和类别 CUSTOM 的中止代码。如果原因不适合 56 位,将中止。 + +```move + public fun custom(reason: u64): u64; +``` + +--------------------------------------------------------------------------- + +## fixed_point32 + + +The `fixed_point32` module defines a fixed-point numeric type with 32 integer bits and 32 fractional bits. Internally, this is represented as a `u64` integer wrapped in a struct to make a unique `fixed_point32` type. Since the numeric representation is a binary one, some decimal values may not be exactly representable, but it provides more than 9 decimal digits of precision both before and after the decimal point (18 digits total). For comparison, double precision floating-point has less than 16 decimal digits of precision, so you should be careful about using floating-point to convert these values to decimal. + +## 固定点32 +fixed_point32 模块定义了一个具有 32 个整数位和 32 个小数位的定点数值类型。在内部,这表示为一个包裹在结构中的 u64 整数,以形成唯一的 fixed_point32 类型。由于数字表示是二进制的,因此某些十进制值可能无法精确表示,但它在小数点前后都提供了超过 9 位的精度(总共 18 位)。作为比较,双精度浮点的精度小于 16 位小数,因此在使用浮点将这些值转换为十进制时应小心。 + +### Types + +Represents a fixed-point numeric number with 32 fractional bits. + +### 类型 + +表示具有 32 个小数位的定点数值。 + +```move + struct FixedPoint32; +``` + +### Functions + +Multiply a u64 integer by a fixed-point number, truncating any fractional part of the product. This will abort if the product overflows. + +### 函数 + +将 u64 整数乘以定点数,截断乘积的任何小数部分。如果产品溢出,这将中止。 +```move + public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64; +``` + +--------------------------------------------------------------------------- +Divide a u64 integer by a fixed-point number, truncating any fractional part of the quotient. This will abort if the divisor is zero or if the quotient overflows. + +将 u64 整数除以定点数,截断商的任何小数部分。如果除数为零或商溢出,这将中止。 + +```move + public fun divide_u64(val: u64, divisor: FixedPoint32): u64; +``` + +--------------------------------------------------------------------------- +Create a fixed-point value from a rational number specified by its numerator and denominator. Calling this function should be preferred for using `fixed_point32::create_from_raw_value` which is also available. This will abort if the denominator is zero. It will also abort if the numerator is nonzero and the ratio is not in the range $2^{-32}\ldots2^{32}-1$. When specifying decimal fractions, be careful about rounding errors: if you round to display $N$ digits after the decimal point, you can use a denominator of $10^N$ to avoid numbers where the very small imprecision in the binary representation could change the rounding, e.g., 0.0125 will round down to 0.012 instead of up to 0.013. + +根据分子和分母指定的有理数创建定点值。使用也可用的 fixed_point32::create_from_raw_value 应该首选调用此函数。如果分母为零,这将中止。如果分子不为零并且比率不在 $2 +{-32}ldots2 +{32}-1$ 范围内,它也会中止。指定小数时,请注意舍入错误:如果四舍五入以显示小数点后的 $N$ 个数字,则可以使用分母 $10 +N$ 来避免二进制表示中非常小的不精确性可能会改变四舍五入,例如,0.0125 将向下舍入为 0.012,而不是向上舍入为 0.013。 + +```move + public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32; +``` + +--------------------------------------------------------------------------- +Create a fixedpoint value from a raw `u64` value. + +从原始 u64 值创建定点值。 + +```move + public fun create_from_raw_value(value: u64): FixedPoint32; +``` + +--------------------------------------------------------------------------- +Returns `true` if the decimal value of `num` is equal to zero. + +如果 num 的十进制值等于 0,则返回 true。 + +```move + public fun is_zero(num: FixedPoint32): bool; +``` + +--------------------------------------------------------------------------- +Accessor for the raw `u64` value. Other less common operations, such as adding or subtracting `FixedPoint32` values, can be done using the raw values directly. + +原始 u64 值的访问器。其他不太常见的操作,例如添加或减去 FixedPoint32 值,可以直接使用原始值完成。 + +```move + public fun get_raw_value(num: FixedPoint32): u64; +``` + +--------------------------------------------------------------------------- diff --git a/language/documentation/book/translations/move-book-zh/src/structs-and-resources.md b/language/documentation/book/translations/move-book-zh/src/structs-and-resources.md new file mode 100644 index 0000000000..51193c26a9 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/structs-and-resources.md @@ -0,0 +1,593 @@ +# Structs and Resources + +A _struct_ is a user-defined data structure containing typed fields. Structs can store any +non-reference type, including other structs. + +We often refer to struct values as _resources_ if they cannot be copied and cannot be dropped. In +this case, resource values must have ownership transferred by the end of the function. This property +makes resources particularly well served for defining global storage schemas or for representing +important values (such as a token). + +By default, structs are linear and ephemeral. By this we mean that they: cannot be copied, cannot be +dropped, and cannot be stored in global storage. This means that all values have to have ownership +transferred (linear) and the values must be dealt with by the end of the program's execution +(ephemeral). We can relax this behavior by giving the struct [abilities](./abilities.md) which allow +values to be copied or dropped and also to be stored in global storage or to define global storage +schemas. +# 结构和资源 +结构是包含类型字段的用户定义数据结构。结构可以存储任何非引用类型,包括其他结构。 + +如果结构值无法复制且无法删除,我们通常将其称为资源。在这种情况下,资源值必须在函数结束时转移所有权。此属性使资源特别适合用于定义全局存储模式或表示重要值(例如令牌)。 + +默认情况下,结构是线性的和短暂的。我们的意思是它们:不能被复制,不能被删除,不能被存储在全局存储中。这意味着所有值都必须转移所有权(线性),并且必须在程序执行结束时处理这些值(临时)。我们可以通过赋予 struct 允许复制或删除值以及存储在全局存储中或定义全局存储模式的能力来放松这种行为。 + +## Defining Structs + +Structs must be defined inside a module: +## 定义结构 +结构必须在模块内定义: + +```move +address 0x2 { +module m { + struct Foo { x: u64, y: bool } + struct Bar {} + struct Baz { foo: Foo, } + // ^ note: it is fine to have a trailing comma +} +} +``` + +Structs cannot be recursive, so the following definition is invalid: +结构不能递归,所以下面的定义是无效的: + +```move= +struct Foo { x: Foo } +// ^ error! Foo cannot contain Foo +``` + +As mentioned above: by default, a struct declaration is linear and ephemeral. So to allow the value +to be used with certain operations (that copy it, drop it, store it in global storage, or use it as +a storage schema), structs can be granted [abilities](./abilities.md) by annotating them with +`has `: + +如上所述:默认情况下,结构声明是线性且短暂的。因此,为了允许将值用于某些操作(复制、删除、将其存储在全局存储中或将其用作存储模式),可以通过使用 has ability 注释它们来授予结构能力: + +```move= +address 0x2 { +module m { + struct Foo has copy, drop { x: u64, y: bool } +} +} +``` + +For more details, see the [annotating structs](./abilities.md#annotating-structs) section. +有关更多详细信息,请参阅注释结构部分。 + +### Naming + +Structs must start with a capital letter `A` to `Z`. After the first letter, constant names can +contain underscores `_`, letters `a` to `z`, letters `A` to `Z`, or digits `0` to `9`. +### 命名 +结构必须以大写字母 A 到 Z 开头。在第一个字母之后,常量名称可以包含下划线 `_`、字母 a 到 z、字母 A 到 Z 或数字 0 到 9。 + +```move +struct Foo {} +struct BAR {} +struct B_a_z_4_2 {} +``` + +This naming restriction of starting with `A` to `Z` is in place to give room for future language +features. It may or may not be removed later. + +这种以 A 到 Z 开头的命名限制是为了给未来的语言特性留出空间。以后可能会或可能不会删除它。 + +## Using Structs + +### Creating Structs + +Values of a struct type can be created (or "packed") by indicating the struct name, followed by +value for each field: +## 使用结构 +### 创建结构 +可以通过指示结构名称来创建(或“打包”)结构类型的值,然后是每个字段的值: + +```move= +address 0x2 { +module m { + struct Foo has drop { x: u64, y: bool } + struct Baz has drop { foo: Foo } + + fun example() { + let foo = Foo { x: 0, y: false }; + let baz = Baz { foo: foo }; + } +} +} +``` + +If you initialize a struct field with a local variable whose name is the same as the field, you can +use the following shorthand: + +如果使用与字段名称相同的局部变量初始化结构字段,则可以使用以下简写: + +```move +let baz = Baz { foo: foo }; +// is equivalent to +let baz = Baz { foo }; +``` + +This is called sometimes called "field name punning". + +这有时称为“字段名称双关语”。 + +### Destroying Structs via Pattern Matching + +Struct values can be destroyed by binding or assigning them patterns. +### 通过模式匹配销毁结构 +结构值可以通过绑定或分配模式来销毁。 + +```move= +address 0x2 { +module m { + struct Foo { x: u64, y: bool } + struct Bar { foo: Foo } + struct Baz {} + + fun example_destroy_foo() { + let foo = Foo { x: 3, y: false }; + let Foo { x, y: foo_y } = foo; + // ^ shorthand for `x: x` + + // two new bindings + // x: u64 = 3 + // foo_y: bool = false + } + + fun example_destroy_foo_wildcard() { + let foo = Foo { x: 3, y: false }; + let Foo { x, y: _ } = foo; + // only one new binding since y was bound to a wildcard + // x: u64 = 3 + } + + fun example_destroy_foo_assignment() { + let x: u64; + let y: bool; + Foo { x, y } = Foo { x: 3, y: false }; + // mutating existing variables x & y + // x = 3, y = false + } + + fun example_foo_ref() { + let foo = Foo { x: 3, y: false }; + let Foo { x, y } = &foo; + // two new bindings + // x: &u64 + // y: &bool + } + + fun example_foo_ref_mut() { + let foo = Foo { x: 3, y: false }; + let Foo { x, y } = &mut foo; + // two new bindings + // x: &mut u64 + // y: &mut bool + } + + fun example_destroy_bar() { + let bar = Bar { foo: Foo { x: 3, y: false } }; + let Bar { foo: Foo { x, y } } = bar; + // ^ nested pattern + // two new bindings + // x: u64 = 3 + // foo_y: bool = false + } + + fun example_destroy_baz() { + let baz = Baz {}; + let Baz {} = baz; + } +} +} +``` + +### Borrowing Structs and Fields + +The `&` and `&mut` operator can be used to create references to structs or fields. These examples +include some optional type annotations (e.g., `: &Foo`) to demonstrate the type of operations. + +### 借用结构和字段 +& 和 &mut 运算符可用于创建对结构或字段的引用。这些示例包括一些可选的类型注释(例如:&Foo)来演示操作的类型。 + +```move= +let foo = Foo { x: 3, y: true }; +let foo_ref: &Foo = &foo; +let y: bool = foo_ref.y; // reading a field via a reference to the struct +let x_ref: &u64 = &foo.x; + +let x_ref_mut: &mut u64 = &mut foo.x; +*x_ref_mut = 42; // modifying a field via a mutable reference +``` + +It is possible to borrow inner fields of nested structs. + +可以借用嵌套结构的内部字段。 + +```move= +let foo = Foo { x: 3, y: true }; +let bar = Bar { foo }; + +let x_ref = &bar.foo.x; +``` + +You can also borrow a field via a reference to a struct. + +您还可以通过对结构的引用来借用字段。 + +```move= +let foo = Foo { x: 3, y: true }; +let foo_ref = &foo; +let x_ref = &foo_ref.x; +// this has the same effect as let x_ref = &foo.x +``` + +### Reading and Writing Fields + +If you need to read and copy a field's value, you can then dereference the borrowed field +### 阅读和写作领域 +如果您需要读取和复制字段的值,则可以取消引用借用的字段 + +```move= +let foo = Foo { x: 3, y: true }; +let bar = Bar { foo: copy foo }; +let x: u64 = *&foo.x; +let y: bool = *&foo.y; +let foo2: Foo = *&bar.foo; +``` + +If the field is implicitly copyable, the dot operator can be used to read fields of a struct without +any borrowing. (Only scalar values with the `copy` ability are implicitly copyable.) + +如果该字段是隐式可复制的,则点运算符可用于读取结构的字段而无需任何借用。 (只有具有复制能力的标量值是隐式可复制的。) + +```move= +let foo = Foo { x: 3, y: true }; +let x = foo.x; // x == 3 +let y = foo.y; // y == true +``` + +Dot operators can be chained to access nested fields. + +点运算符可以链接起来访问嵌套字段。 + +```move= +let baz = Baz { foo: Foo { x: 3, y: true } }; +let x = baz.foo.x; // x = 3; +``` + +However, this is not permitted for fields that contain non-primitive types, such a vector or another +struct + +但是,对于包含非原始类型(例如向量或其他结构)的字段,这是不允许的 + +```move= +let foo = Foo { x: 3, y: true }; +let bar = Bar { foo }; +let foo2: Foo = *&bar.foo; +let foo3: Foo = bar.foo; // error! add an explicit copy with *& +``` + +The reason behind this design decision is that copying a vector or another struct might be an +expensive operation. It is important for a programmer to be aware of this copy and make others aware +with the explicit syntax `*&` + +In addition reading from fields, the dot syntax can be used to modify fields, regardless of the +field being a primitive type or some other struct + +这个设计决策背后的原因是复制一个向量或另一个结构可能是一项昂贵的操作。对于程序员来说,了解这个副本并使用显式语法 `*&` 让其他人了解是很重要的 + +除了从字段中读取之外,点语法还可用于修改字段,无论该字段是原始类型还是其他结构 + +```move= +let foo = Foo { x: 3, y: true }; +foo.x = 42; // foo = Foo { x: 42, y: true } +foo.y = !foo.y; // foo = Foo { x: 42, y: false } +let bar = Bar { foo }; // bar = Bar { foo: Foo { x: 42, y: false } } +bar.foo.x = 52; // bar = Bar { foo: Foo { x: 52, y: false } } +bar.foo = Foo { x: 62, y: true }; // bar = Bar { foo: Foo { x: 62, y: true } } +``` + +The dot syntax also works via a reference to a struct + +点语法也可以通过对结构的引用来工作 + +```move= +let foo = Foo { x: 3, y: true }; +let foo_ref = &mut foo; +foo_ref.x = foo_ref.x + 1; +``` + +## Privileged Struct Operations + +Most struct operations on a struct type `T` can only be performed inside the module that declares +`T`: + +- Struct types can only be created ("packed"), destroyed ("unpacked") inside the module that defines + the struct. +- The fields of a struct are only accessible inside the module that defines the struct. + +Following these rules, if you want to modify your struct outside the module, you will need to +provide publis APIs for them. The end of the chapter contains some examples of this. + +However, struct _types_ are always visible to another module or script: +## 特权结构操作 +大多数对结构类型 T 的结构操作只能在声明 T 的模块内执行: + +- 结构类型只能在定义结构的模块内创建(“打包”)、销毁(“解包”)。 +- 结构的字段只能在定义结构的模块内部访问。 +遵循这些规则,如果你想在模块之外修改你的结构,你需要为它们提供 publis API。本章的最后包含了这方面的一些例子。 + +但是,结构类型始终对另一个模块或脚本可见: + +```move= +// m.move +address 0x2 { +module m { + struct Foo has drop { x: u64 } + + public fun new_foo(): Foo { + Foo { x: 42 } + } +} +} +``` + +```move= +// n.move +address 0x2 { +module n { + use 0x2::m; + + struct Wrapper has drop { + foo: m::Foo + } + + fun f1(foo: m::Foo) { + let x = foo.x; + // ^ error! cannot access fields of `foo` here + } + + fun f2() { + let foo_wrapper = Wrapper { foo: m::new_foo() }; + } +} +} +``` + +Note that structs do not have visibility modifiers (e.g., `public` or `private`). + +请注意,结构没有可见性修饰符(例如,公共或私有)。 + +## Ownership + +As mentioned above in [Defining Structs](#defining-structs), structs are by default linear and +ephemeral. This means they cannot be copied or dropped. This property can be very useful when +modeling real world resources like money, as you do not want money to be duplicated or get lost in +circulation. +## 所有权 +正如上面定义结构中提到的,结构默认是线性的和短暂的。这意味着它们不能被复制或删除。在模拟货币等现实世界资源时,此属性非常有用,因为您不希望货币被复制或在流通中丢失。 + +```move= +address 0x2 { +module m { + struct Foo { x: u64 } + + public fun copying_resource() { + let foo = Foo { x: 100 }; + let foo_copy = copy foo; // error! 'copy'-ing requires the 'copy' ability + let foo_ref = &foo; + let another_copy = *foo_ref // error! dereference requires the 'copy' ability + } + + public fun destroying_resource1() { + let foo = Foo { x: 100 }; + + // error! when the function returns, foo still contains a value. + // This destruction requires the 'drop' ability + } + + public fun destroying_resource2(f: &mut Foo) { + *f = Foo { x: 100 } // error! + // destroying the old value via a write requires the 'drop' ability + } +} +} +``` + +To fix the second example (`fun dropping_resource`), you would need to manually "unpack" the +resource: + +要修复第二个示例(有趣的 drop_resource),您需要手动“解包”资源: + +```move= +address 0x2 { +module m { + struct Foo { x: u64 } + + public fun destroying_resource1_fixed() { + let foo = Foo { x: 100 }; + let Foo { x: _ } = foo; + } +} +} +``` + +Recall that you are only able to deconstruct a resource within the module in which it is defined. +This can be leveraged to enforce certain invariants in a system, for example, conservation of money. + +If on the other hand, your struct does not represent something valuable, you can add the abilities +`copy` and `drop` to get a struct value that might feel more familiar from other programming +languages: + +回想一下,您只能在定义资源的模块中解构资源。这可以用来在系统中强制执行某些不变量,例如货币守恒。 + +另一方面,如果您的结构不代表有价值的东西,您可以添加功能复制和删除以获取可能对其他编程语言更熟悉的结构值: + +```move= +address 0x2 { +module m { + struct Foo has copy, drop { x: u64 } + + public fun run() { + let foo = Foo { x: 100 }; + let foo_copy = copy foo; + // ^ this code copies foo, whereas `let x = foo` or + // `let x = move foo` both move foo + + let x = foo.x; // x = 100 + let x_copy = foo_copy.x; // x = 100 + + // both foo and foo_copy are implicitly discarded when the function returns + } +} +} +``` + +## Storing Resources in Global Storage + +Only structs with the `key` ability can be saved directly in +[persistent global storage](./global-storage-operators.md). All values stored within those `key` +structs must have the `store` abilities. See the [ability](./abilities) and +[global storage](./global-storage-operators.md) chapters for more detail. + +## 在全局存储中存储资源 +只有具有关键能力的结构才能直接保存在持久性全局存储中。存储在这些键结构中的所有值都必须具有存储能力。有关更多详细信息,请参阅能力和全局存储章节。 + +## Examples + +Here are two short examples of how you might use structs to represent valuable data (in the case of +`Coin`) or more classical data (in the case of `Point` and `Circle`) +## 例子 +这里有两个简短的示例,说明如何使用结构来表示有价值的数据(在 Coin 的情况下)或更经典的数据(在 Point 和 Circle 的情况下) + +### Example 1: Coin +### 示例 1:硬币 + + + +```move= +address 0x2 { +module m { + // We do not want the Coin to be copied because that would be duplicating this "money", + // so we do not give the struct the 'copy' ability. + // Similarly, we do not want programmers to destroy coins, so we do not give the struct the + // 'drop' ability. + // However, we *want* users of the modules to be able to store this coin in persistent global + // storage, so we grant the struct the 'store' ability. This struct will only be inside of + // other resources inside of global storage, so we do not give the struct the 'key' ability. + struct Coin has store { + value: u64, + } + + public fun mint(value: u64): Coin { + // You would want to gate this function with some form of access control to prevent + // anyone using this module from minting an infinite amount of coins + Coin { value } + } + + public fun withdraw(coin: &mut Coin, amount: u64): Coin { + assert!(coin.balance >= amount, 1000); + coin.value = coin.value - amount; + Coin { value: amount } + } + + public fun deposit(coin: &mut Coin, other: Coin) { + let Coin { value } = other; + coin.value = coin.value + value; + } + + public fun split(coin: Coin, amount: u64): (Coin, Coin) { + let other = withdraw(&mut coin, amount); + (coin, other) + } + + public fun merge(coin1: Coin, coin2: Coin): Coin { + deposit(&mut coin1, coin2); + coin1 + } + + public fun destroy_zero(coin: Coin) { + let Coin { value } = coin; + assert!(value == 0, 1001); + } +} +} +``` + +### Example 2: Geometry +### 示例 2:几何 + +```move= +address 0x2 { +module point { + struct Point has copy, drop, store { + x: u64, + y: u64, + } + + public fun new(x: u64, y: u64): Point { + Point { + x, y + } + } + + public fun x(p: &Point): u64 { + p.x + } + + public fun y(p: &Point): u64 { + p.y + } + + fun abs_sub(a: u64, b: u64): u64 { + if (a < b) { + b - a + } + else { + a - b + } + } + + public fun dist_squared(p1: &Point, p2: &Point): u64 { + let dx = abs_sub(p1.x, p2.x); + let dy = abs_sub(p1.y, p2.y); + dx*dx + dy*dy + } +} +} +``` + +```move= +address 0x2 { +module circle { + use 0x2::Point::{Self, Point}; + + struct Circle has copy, drop, store { + center: Point, + radius: u64, + } + + public fun new(center: Point, radius: u64): Circle { + Circle { center, radius } + } + + public fun overlaps(c1: &Circle, c2: &Circle): bool { + let d = Point::dist_squared(&c1.center, &c2.center); + let r1 = c1.radius; + let r2 = c2.radius; + d*d <= r1*r1 + 2*r1*r2 + r2*r2 + } +} +} +``` diff --git a/language/documentation/book/translations/move-book-zh/src/tuples.md b/language/documentation/book/translations/move-book-zh/src/tuples.md new file mode 100644 index 0000000000..51bd2bd66d --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/tuples.md @@ -0,0 +1,162 @@ +# Tuples and Unit + +Move does not fully support tuples as one might expect coming from another language with them as a +first-class value. However, in order to support multiple return values, Move has tuple-like +expressions. These expressions do not result in a concrete value at runtime (there are no tuples in +the bytecode), and as a result they are very limited: they can only appear in expressions (usually +in the return position for a function); they cannot be bound to local variables; they cannot be +stored in structs; and tuple types cannot be used to instantiate generics. + +Similarly, unit `()` is a type created by the Move source language in order to be expression based. +The unit value `()` does not result in any runtime value. We can consider unit`()` to be an empty +tuple, and any restrictions that apply to tuples also apply to unit. + +It might feel weird to have tuples in the language at all given these restrictions. But one of the +most common use cases for tuples in other languages is for functions to allow functions to return +multiple values. Some languages work around this by forcing the users to write structs that contain +the multiple return values. However in Move, you cannot put references inside of +[structs](./structs-and-resources.md). This required Move to support multiple return values. These +multiple return values are all pushed on the stack at the bytecode level. At the source level, these +multiple return values are represented using tuples. +# 元组和单元 +Move 不完全支持元组,因为人们可能期望来自另一种语言的元组将它们作为一等值。但是,为了支持多个返回值,Move 具有类似元组的表达式。这些表达式在运行时不会产生具体的值(字节码中没有元组),因此它们非常有限:它们只能出现在表达式中(通常在函数的返回位置);它们不能绑定到局部变量;它们不能存储在结构中;元组类型不能用于实例化泛型。 + +类似地,unit() 是 Move 源语言创建的一种类型,以便基于表达式。单位值 () 不会产生任何运行时值。我们可以认为 unit() 是一个空元组,适用于元组的任何限制也适用于 unit。 + +考虑到这些限制,在语言中使用元组可能会感觉很奇怪。但其他语言中元组最常见的用例之一是函数允许函数返回多个值。一些语言通过强制用户编写包含多个返回值的结构来解决这个问题。但是在 Move 中,您不能将引用放在结构中。这需要 Move 支持多个返回值。这些多个返回值都在字节码级别被压入堆栈。在源级别,这些多个返回值使用元组表示。 + +## Literals + +Tuples are created by a comma separated list of expressions inside of parentheses +## 字面量 +元组由括号内的逗号分隔的表达式列表创建 + +| Syntax | Type | Description | +| --------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------ | +| `()` | `(): ()` | Unit, the empty tuple, or the tuple of arity 0 | +| `(e1, ..., en)` | `(e1, ..., en): (T1, ..., Tn)` where `e_i: Ti` s.t. `0 < i <= n` and `n > 0` | A `n`-tuple, a tuple of arity `n`, a tuple with `n` elements | + +Note that `(e)` does not have type `(e): (t)`, in other words there is no tuple with one element. If +there is only a single element inside of the parentheses, the parentheses are only used for +disambiguation and do not carry any other special meaning. + +Sometimes, tuples with two elements are called "pairs" and tuples with three elements are called +"triples." + +注意 (e) 没有类型 (e): (t),换句话说,没有一个元素的元组。如果括号内只有一个元素,则括号仅用于消歧,不带有任何其他特殊含义。 + +有时,具有两个元素的元组称为“对”,而具有三个元素的元组称为“三元组”。 + +### Examples +### 例子 + +```move= +address 0x42 { +module example { + // all 3 of these functions are equivalent + + // when no return type is provided, it is assumed to be `()` + fun returs_unit_1() { } + + // there is an implicit () value in empty expression blocks + fun returs_unit_2(): () { } + + // explicit version of `returs_unit_1` and `returs_unit_2` + fun returs_unit_3(): () { () } + + + fun returns_3_values(): (u64, bool, address) { + (0, false, @0x42) + } + fun returns_4_values(x: &u64): (&u64, u8, u128, vector) { + (x, 0, 1, b"foobar") + } +} +} +``` + +## Operations + +The only operation that can be done on tuples currently is destructuring. + +### Destructuring + +For tuples of any size, they can be destructured in either a `let` binding or in an assignment. + +For example: +## 运营 +目前可以对元组进行的唯一操作是解构。 + +### 解构 +对于任何大小的元组,它们可以在 let 绑定或赋值中解构。 + +例如: + +```move= +address 0x42 { +module example { + // all 3 of these functions are equivalent + fun returns_unit() {} + fun returns_2_values(): (bool, bool) { (true, false) } + fun returns_4_values(x: &u64): (&u64, u8, u128, vector) { (x, 0, 1, b"foobar") } + + fun examples(cond: bool) { + let () = (); + let (x, y): (u8, u64) = (0, 1); + let (a, b, c, d) = (@0x0, 0, false, b""); + + () = (); + (x, y) = if (cond) (1, 2) else (3, 4); + (a, b, c, d) = (@0x1, 1, true, b"1"); + } + + fun examples_with_function_calls() { + let () = returns_unit(); + let (x, y): (bool, bool) = returns_2_values(); + let (a, b, c, d) = returns_4_values(&0); + + () = returns_unit(); + (x, y) = returns_2_values(); + (a, b, c, d) = returns_4_values(&1); + } +} +} +``` + +For more details, see [Move Variables](./variables.md). +有关更多详细信息,请参阅移动变量。 + +## Subtyping + +Along with references, tuples are the only types that have subtyping in Move. Tuples do have +subtyping only in the sense that subtype with references (in a covariant way). + +For example +## 子类型化 +除了引用,元组是唯一在 Move 中具有子类型的类型。元组只有在具有引用的子类型(以协变方式)的意义上才具有子类型。 + +例如 + +```move= +let x: &u64 = &0; +let y: &mut u64 = &mut 1; + +// (&u64, &mut u64) is a subtype of (&u64, &u64) +// since &mut u64 is a subtype of &u64 +let (a, b): (&u64, &u64) = (x, y); +// (&mut u64, &mut u64) is a subtype of (&u64, &u64) +// since &mut u64 is a subtype of &u64 +let (c, d): (&u64, &u64) = (y, y); +// error! (&u64, &mut u64) is NOT a subtype of (&mut u64, &mut u64) +// since &u64 is NOT a subtype of &mut u64 +let (e, f): (&mut u64, &mut u64) = (x, y); +``` + +## Ownership + +As mentioned above, tuple values don't really exist at runtime. And currently they cannot be stored +into local variables because of this (but it is likely that this feature will come soon). As such, +tuples can only be moved currently, as copying them would require putting them into a local variable +first. +## 所有权 +如上所述,元组值在运行时并不真正存在。由于这个原因,目前它们不能存储到局部变量中(但这个功能很可能很快就会出现)。因此,元组目前只能移动,因为复制它们需要先将它们放入局部变量中。 diff --git a/language/documentation/book/translations/move-book-zh/src/unit-testing.md b/language/documentation/book/translations/move-book-zh/src/unit-testing.md new file mode 100644 index 0000000000..1239de4d5e --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/unit-testing.md @@ -0,0 +1,376 @@ +# Unit Tests + +Unit testing for Move adds three new annotations to the Move source language: + +* `#[test]` +* `#[test_only]`, and +* `#[expected_failure]`. + +They respectively mark a function as a test, mark a module or module member (`use`, function, or struct) as code to be included for testing only, and mark that a test is expected to fail. These annotations can be placed on a function with any visibility. Whenever a module or module member is annotated as `#[test_only]` or `#[test]`, it will not be included in the compiled bytecode unless it is compiled for testing. +# 单元测试 +Move 的单元测试为 Move 源语言添加了三个新注释: + +* #[test] +* #[test_only],和 +* #[expected_failure]。 + +它们分别将函数标记为测试,将模块或模块成员(使用、函数或结构)标记为仅用于测试的代码,并标记预期测试将失败。这些注释可以放置在具有任何可见性的函数上。每当一个模块或模块成员被注释为 `#[test_only]` 或 `#[test]` 时,它不会包含在编译的字节码中,除非它被编译用于测试。 + +## Testing Annotations: Their Meaning and Usage + +Both the `#[test]` and `#[expected_failure]` annotations can be used either with or without arguments. + +Without arguments, the `#[test]` annotation can only be placed on a function with no parameters. This annotation simply marks this function as a test to be run by the unit testing harness. + +## 测试注释:它们的含义和用法 +`#[test]` 和 `#[expected_failure]` 注释都可以带或不带参数使用。 + +没有参数,#[test] 注释只能放在没有参数的函数上。此注释只是将此函数标记为要由单元测试工具运行的测试。 + +``` +#[test] // OK +fun this_is_a_test() { ... } + +#[test] // Will fail to compile since the test takes an argument +fun this_is_not_correct(arg: signer) { ... } +``` + +A test can also be annotated as an `#[expected_failure]`. This annotation marks that the test should is expected to raise an error. You can ensure that a test is aborting with a specific abort code by annotating it with `#[expected_failure(abort_code = )]`, if it then fails with a different abort code or with a non-abort error the test will fail. Only functions that have the `#[test]` annotation can also be annotated as an #`[expected_failure]`. + +测试也可以注释为 `#[expected_failure]`。此注释标志着测试应该会引发错误。您可以通过使用 `#[expected_failure(abort_code = code)]` 对其进行注释来确保测试使用特定的中止代码中止,如果它随后因不同的中止代码或非中止错误而失败,则测试将失败。只有具有 `#[test]` 注释的函数也可以注释为 `#[expected_failure]`。 + +``` +#[test] +#[expected_failure] +public fun this_test_will_abort_and_pass() { abort 1 } + +#[test] +#[expected_failure] +public fun test_will_error_and_pass() { 1/0; } + +#[test] +#[expected_failure(abort_code = 0)] +public fun test_will_error_and_fail() { 1/0; } + +#[test, expected_failure] // Can have multiple in one attribute. This test will pass. +public fun this_other_test_will_abort_and_pass() { abort 1 } +``` + +With arguments, a test annotation takes the form `#[test( =
, ..., =
)]`. If a function is annotated in such a manner, the function's parameters must be a permutation of the parameters <`param_name_1>, ..., `, i.e., the order of these parameters as they occur in the function and their order in the test annotation do not have to be the same, but they must be able to be matched up with each other by name. + +Only parameters with a type of `signer` are supported as test parameters. If a non-`signer` parameter is supplied, the test will result in an error when run. + +带有参数的测试注解采用 `#[test( param_name_1 = address , ..., param_name_n = address )]` 的形式。如果以这种方式注释函数,则函数的参数必须是参数 param_name_1 , ..., param_name_n 的排列,即这些参数在函数中出现的顺序和它们在测试注释中的顺序不必须相同,但它们必须能够通过名称相互匹配。 + +仅支持具有签名者类型的参数作为测试参数。如果提供了非签名者参数,则测试将在运行时导致错误。 + +``` +#[test(arg = @0xC0FFEE)] // OK +fun this_is_correct_now(arg: signer) { ... } + +#[test(wrong_arg_name = @0xC0FFEE)] // Not correct: arg name doesn't match +fun this_is_incorrect(arg: signer) { ... } + +#[test(a = @0xC0FFEE, b = @0xCAFE)] // OK. We support multiple signer arguments, but you must always provide a value for that argument +fun this_works(a: signer, b: signer) { ... } + +// somewhere a named address is declared +#[test_only] // test-only named addresses are supported +address TEST_NAMED_ADDR = @0x1; +... +#[test(arg = @TEST_NAMED_ADDR)] // Named addresses are supported! +fun this_is_correct_now(arg: signer) { ... } +``` + +An expected failure annotation can also take the form `#[expected_failure(abort_code = )]`. If a test function is annotated in such a way, the test must abort with an abort code equal to ``. Any other failure or abort code will result in a test failure. + +预期的失败注释也可以采用 #[expected_failure(abort_code = u64)] 的形式。如果以这种方式注释测试函数,则必须使用等于 u64 的中止代码中止测试。任何其他失败或中止代码都将导致测试失败。 + +``` +#[test, expected_failure(abort_code = 1)] // This test will fail +fun this_test_should_abort_and_fail() { abort 0 } + +#[test] +#[expected_failure(abort_code = 0)] // This test will pass +fun this_test_should_abort_and_pass_too() { abort 0 } +``` + +A module and any of its members can be declared as test only. In such a case the item will only be included in the compiled Move bytecode when compiled in test mode. Additionally, when compiled outside of test mode, any non-test `use`s of a `#[test_only]` module will raise an error during compilation. + +一个模块及其任何成员都可以声明为仅测试。在这种情况下,只有在测试模式下编译时,该项目才会包含在编译后的 Move 字节码中。此外,在测试模式之外编译时,#[test_only] 模块的任何非测试使用都会在编译期间引发错误。 + +``` +#[test_only] // test only attributes can be attached to modules +module abc { ... } + +#[test_only] // test only attributes can be attached to named addresses +address ADDR = @0x1; + +#[test_only] // .. to uses +use 0x1::some_other_module; + +#[test_only] // .. to structs +struct SomeStruct { ... } + +#[test_only] // .. and functions. Can only be called from test code, but not a test +fun test_only_function(...) { ... } +``` + +## Running Unit Tests + +Unit tests for a Move package can be run with the [`move test` +command](./packages.md). + +When running tests, every test will either `PASS`, `FAIL`, or `TIMEOUT`. If a test case fails, the location of the failure along with the function name that caused the failure will be reported if possible. You can see an example of this below. + +A test will be marked as timing out if it exceeds the maximum number of instructions that can be executed for any single test. This bound can be changed using the options below, and its default value is set to 5000 instructions. Additionally, while the result of a test is always deterministic, tests are run in parallel by default, so the ordering of test results in a test run is non-deterministic unless running with only one thread (see `OPTIONS` below). + +There are also a number of options that can be passed to the unit testing binary to fine-tune testing and to help debug failing tests. These can be found using the the help flag: +## 运行单元测试 +可以使用 move test 命令运行 Move 包的单元测试。 + +运行测试时,每个测试都将通过、失败或超时。如果测试用例失败,将尽可能报告失败的位置以及导致失败的函数名称。您可以在下面看到一个示例。 + +如果测试超过任何单个测试可以执行的最大指令数,则测试将被标记为超时。可以使用以下选项更改此界限,其默认值设置为 5000 条指令。此外,虽然测试的结果始终是确定性的,但默认情况下测试是并行运行的,因此测试运行中测试结果的顺序是不确定的,除非仅使用一个线程运行(请参阅下面的选项)。 + +还有许多选项可以传递给单元测试二进制文件以微调测试并帮助调试失败的测试。这些可以使用帮助标志找到: + +``` +$ move -h +``` + +## Example + +A simple module using some of the unit testing features is shown in the following example: + +First create an empty package and change directory into it: + +## 例子 +以下示例显示了使用一些单元测试功能的简单模块: + +首先创建一个空包并将目录更改为它: + +``` +$ move new TestExample; cd TestExample +``` + +Next add the following to the `Move.toml`: + +接下来将以下内容添加到 Move.toml: + +``` +[dependencies] +MoveStdlib = { git = "https://github.com/diem/diem.git", subdir="language/move-stdlib", rev = "56ab033cc403b489e891424a629e76f643d4fb6b", addr_subst = { "std" = "0x1" } } +``` + +Next add the following module under the `sources` directory: + +接下来在源目录下添加以下模块: + +``` +// filename: sources/my_module.move +module 0x1::my_module { + + struct MyCoin has key { value: u64 } + + public fun make_sure_non_zero_coin(coin: MyCoin): MyCoin { + assert!(coin.value > 0, 0); + coin + } + + public fun has_coin(addr: address): bool { + exists(addr) + } + + #[test] + fun make_sure_non_zero_coin_passes() { + let coin = MyCoin { value: 1 }; + let MyCoin { value: _ } = make_sure_non_zero_coin(coin); + } + + #[test] + // Or #[expected_failure] if we don't care about the abort code + #[expected_failure(abort_code = 0)] + fun make_sure_zero_coin_fails() { + let coin = MyCoin { value: 0 }; + let MyCoin { value: _ } = make_sure_non_zero_coin(coin); + } + + #[test_only] // test only helper function + fun publish_coin(account: &signer) { + move_to(account, MyCoin { value: 1 }) + } + + #[test(a = @0x1, b = @0x2)] + fun test_has_coin(a: signer, b: signer) { + publish_coin(&a); + publish_coin(&b); + assert!(has_coin(@0x1), 0); + assert!(has_coin(@0x2), 1); + assert!(!has_coin(@0x3), 1); + } +} +``` + +### Running Tests + +You can then run these tests with the `move test` command: + +### 运行测试 + +然后,您可以使用 move test 命令运行这些测试: + +``` +$ move test +BUILDING MoveStdlib +BUILDING TestExample +Running Move unit tests +[ PASS ] 0x1::my_module::make_sure_non_zero_coin_passes +[ PASS ] 0x1::my_module::make_sure_zero_coin_fails +[ PASS ] 0x1::my_module::test_has_coin +Test result: OK. Total tests: 3; passed: 3; failed: 0 +``` + +### Using Test Flags + +#### `-f ` or `--filter ` +This will only run tests whose fully qualified name contains ``. For example if we wanted to only run tests with `"zero_coin"` in their name: + +### 使用测试标志 +#### `-f ` 或 `--filter ` +这只会运行完全限定名称包含 str 的测试。例如,如果我们只想运行名称中带有“zero_coin”的测试: + +``` +$ move test -f zero_coin +CACHED MoveStdlib +BUILDING TestExample +Running Move unit tests +[ PASS ] 0x1::my_module::make_sure_non_zero_coin_passes +[ PASS ] 0x1::my_module::make_sure_zero_coin_fails +Test result: OK. Total tests: 2; passed: 2; failed: 0 +``` + +#### `-i ` or `--instructions ` +This bounds the number of instructions that can be executed for any one test to ``: + +#### `-i ` 或 `--instructions ` +这将任何一个测试可以执行的指令数限制为 bound : + +``` +$ move test -i 0 +CACHED MoveStdlib +BUILDING TestExample +Running Move unit tests +[ TIMEOUT ] 0x1::my_module::make_sure_non_zero_coin_passes +[ TIMEOUT ] 0x1::my_module::make_sure_zero_coin_fails +[ TIMEOUT ] 0x1::my_module::test_has_coin + +Test failures: + +Failures in 0x1::my_module: + +┌── make_sure_non_zero_coin_passes ────── +│ Test timed out +└────────────────── + + +┌── make_sure_zero_coin_fails ────── +│ Test timed out +└────────────────── + + +┌── test_has_coin ────── +│ Test timed out +└────────────────── + +Test result: FAILED. Total tests: 3; passed: 0; failed: 3 +``` + +#### `-s` or `--statistics` +With these flags you can gather statistics about the tests run and report the runtime and instructions executed for each test. For example, if we wanted to see the statistics for the tests in the example above: + +#### `-s` 或 `--statistics` + +使用这些标志,您可以收集有关测试运行的统计信息,并报告每个测试的运行时间和执行的指令。例如,如果我们想查看上例中测试的统计信息: + +``` +$ move test -s +CACHED MoveStdlib +BUILDING TestExample +Running Move unit tests +[ PASS ] 0x1::my_module::make_sure_non_zero_coin_passes +[ PASS ] 0x1::my_module::make_sure_zero_coin_fails +[ PASS ] 0x1::my_module::test_has_coin + +Test Statistics: + +┌────────────────────────────────────────────────┬────────────┬───────────────────────────┐ +│ Test Name │ Time │ Instructions Executed │ +├────────────────────────────────────────────────┼────────────┼───────────────────────────┤ +│ 0x1::my_module::make_sure_non_zero_coin_passes │ 0.009 │ 1 │ +├────────────────────────────────────────────────┼────────────┼───────────────────────────┤ +│ 0x1::my_module::make_sure_zero_coin_fails │ 0.008 │ 1 │ +├────────────────────────────────────────────────┼────────────┼───────────────────────────┤ +│ 0x1::my_module::test_has_coin │ 0.008 │ 1 │ +└────────────────────────────────────────────────┴────────────┴───────────────────────────┘ + +Test result: OK. Total tests: 3; passed: 3; failed: 0 +``` + +#### `-g` or `--state-on-error` +These flags will print the global state for any test failures. e.g., if we added the following (failing) test to the `my_module` example: + +#### `-g` 或 `--state-on-error` +这些标志将打印任何测试失败的全局状态。例如,如果我们将以下(失败)测试添加到 my_module 示例中: + +``` +module 0x1::my_module { + ... + #[test(a = @0x1)] + fun test_has_coin_bad(a: signer) { + publish_coin(&a); + assert!(has_coin(@0x1), 0); + assert!(has_coin(@0x2), 1); + } +} +``` + +we would get get the following output when running the tests: + +运行测试时我们会得到以下输出: + +``` +$ move test -g +CACHED MoveStdlib +BUILDING TestExample +Running Move unit tests +[ PASS ] 0x1::my_module::make_sure_non_zero_coin_passes +[ PASS ] 0x1::my_module::make_sure_zero_coin_fails +[ PASS ] 0x1::my_module::test_has_coin +[ FAIL ] 0x1::my_module::test_has_coin_bad + +Test failures: + +Failures in 0x1::my_module: + +┌── test_has_coin_bad ────── +│ error[E11001]: test failure +│ ┌─ /home/tzakian/TestExample/sources/my_module.move:47:10 +│ │ +│ 44 │ fun test_has_coin_bad(a: signer) { +│ │ ----------------- In this function in 0x1::my_module +│ · +│ 47 │ assert!(has_coin(@0x2), 1); +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Test was not expected to abort but it aborted with 1 here +│ +│ +│ ────── Storage state at point of failure ────── +│ 0x1: +│ => key 0x1::my_module::MyCoin { +│ value: 1 +│ } +│ +└────────────────── + +Test result: FAILED. Total tests: 4; passed: 3; failed: 1 +``` diff --git a/language/documentation/book/translations/move-book-zh/src/uses.md b/language/documentation/book/translations/move-book-zh/src/uses.md new file mode 100644 index 0000000000..15b302daa4 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/uses.md @@ -0,0 +1,416 @@ +# Uses and Aliases + +The `use` syntax can be used to create aliases to members in other modules. `use` can be used to +create aliases that last either for the entire module, or for a given expression block scope. +# 用途和别名 +use 语法可用于为其他模块中的成员创建别名。 use 可用于为整个模块或给定的表达式块范围创建别名。 + +## Syntax + +There are several different syntax cases for `use`. Starting with the most simple, we have the +following for creating aliases to other modules +## 句法 +有几种不同的语法案例可供使用。从最简单的开始,我们有以下用于为其他模块创建别名 + +```move +use
::; +use
:: as ; +``` + +For example + +例如 + +```move +use std::vector; +use std::vector as V; +``` + +`use std::vector;` introduces an alias `vector` for `std::vector`. This means that anywhere you +would want to use the module name `std::vector` (assuming this `use` is in scope), you could use +`vector` instead. `use std::vector;` is equivalent to `use std::vector as vector;` + +Similarly `use std::vector as V;` would let you use `V` instead of `std::vector` + +使用标准::向量;为 std::vector 引入别名向量。这意味着在任何您想使用模块名称 std::vector 的地方(假设此使用在范围内),您都可以使用 vector 代替。使用标准::向量;相当于使用 std::vector 作为向量; + +同样使用 std::vector 作为 V;会让你使用 V 而不是 std::vector + +```move= +use std::vector; +use std::vector as V; + +fun new_vecs(): (vector, vector, vector) { + let v1 = std::vector::empty(); + let v2 = vector::empty(); + let v3 = V::empty(); + (v1, v2, v3) +} +``` + +If you want to import a specific module member (such as a function, struct, or constant). You can +use the following syntax. + +如果要导入特定的模块成员(例如函数、结构或常量)。您可以使用以下语法。 + +```move +use
::::; +use
:::: as ; +``` + +For example + +例如 + +```move +use std::vector::empty; +use std::vector::empty as empty_vec; +``` + +This would let you use the function `std::vector::empty` without full qualification. Instead you +could use `empty` and `empty_vec` respectively. Again, `use std::vector::empty;` is equivalent to +`use std::vector::empty as empty;` + +这将允许您在没有完全限定的情况下使用函数 std::vector::empty。相反,您可以分别使用 empty 和 empty_vec。再次,使用 std::vector::empty;相当于使用 std::vector::empty 作为空; + +```move= +use std::vector::empty; +use std::vector::empty as empty_vec; + +fun new_vecs(): (vector, vector, vector) { + let v1 = std::vector::empty(); + let v2 = empty(); + let v3 = empty_vec(); + (v1, v2, v3) +} +``` + +If you want to add aliases for multiple module members at once, you can do so with the following +syntax + +如果要一次为多个模块成员添加别名,可以使用以下语法 + +```move +use
::::{, as ... }; +``` + +For example + +例如 + +```move= +use std::vector::{push_back, length as len, pop_back}; + +fun swap_last_two(v: &mut vector) { + assert!(len(v) >= 2, 42); + let last = pop_back(v); + let second_to_last = pop_back(v); + push_back(v, last); + push_back(v, second_to_last) +} +``` + +If you need to add an alias to the Module itself in addition to module members, you can do that in a +single `use` using `Self`. `Self` is a member of sorts that refers to the module. + +如果除了模块成员之外,您还需要为模块本身添加别名,您可以使用 Self 一次性完成。 Self 是指模块的各种成员。 + +```move +use std::vector::{Self, empty}; +``` + +For clarity, all of the following are equivalent: + +为清楚起见,以下所有内容都是等效的: + +```move +use std::vector; +use std::vector as vector; +use std::vector::Self; +use std::vector::Self as vector; +use std::vector::{Self}; +use std::vector::{Self as vector}; +``` + +If needed, you can have as many aliases for any item as you like + +如果需要,您可以为任何项目设置任意数量的别名 + +```move= +use std::vector::{ + Self, + Self as V, + length, + length as len, +}; + +fun pop_twice(v: &mut vector): (T, T) { + // all options available given the `use` above + assert!(vector::length(v) > 1, 42); + assert!(V::length(v) > 1, 42); + assert!(length(v) > 1, 42); + assert!(len(v) > 1, 42); + + (vector::pop_back(v), vector::pop_back(v)) +} +``` + +## Inside a `module` + +Inside of a `module` all `use` declarations are usable regardless of the order of declaration. +## 模块内部 +在模块内部,无论声明顺序如何,所有 use 声明都是可用的。 + +```move= +address 0x42 { +module example { + use std::vector; + + fun example(): vector { + let v = empty(); + vector::push_back(&mut v, 0); + vector::push_back(&mut v, 10); + v + } + + use std::vector::empty; +} +} +``` + +The aliases declared by `use` in the module usable within that module. + +Additionally, the aliases introduced cannot conflict with other module members. See +[Uniqueness](#uniqueness) for more details + +在该模块中可用的模块中使用声明的别名。 + +此外,引入的别名不能与其他模块成员冲突。有关详细信息,请参阅唯一性 + +## Inside an expression + +You can add `use` declarations to the beginning of any expression block + +## 在表达式内部 +您可以将 use 声明添加到任何表达式块的开头 + +```move= +address 0x42 { +module example { + + fun example(): vector { + use std::vector::{empty, push_back}; + + let v = empty(); + push_back(&mut v, 0); + push_back(&mut v, 10); + v + } +} +} +``` + +As with `let`, the aliases introduced by `use` in an expression block are removed at the end of that +block. + +与 let 一样,在表达式块中使用 use 引入的别名在该块的末尾被删除。 + +```move= +address 0x42 { +module example { + + fun example(): vector { + let result = { + use std::vector::{empty, push_back}; + let v = empty(); + push_back(&mut v, 0); + push_back(&mut v, 10); + v + }; + result + } + +} +} +``` + +Attempting to use the alias after the block ends will result in an error + +在块结束后尝试使用别名将导致错误 + +```move= +fun example(): vector { + let result = { + use std::vector::{empty, push_back}; + let v = empty(); + push_back(&mut v, 0); + push_back(&mut v, 10); + v + }; + let v2 = empty(); // ERROR! +// ^^^^^ unbound function 'empty' + result +} +``` + +Any `use` must be the first item in the block. If the `use` comes after any expression or `let`, it +will result in a parsing error + +任何使用都必须是块中的第一项。如果 use 出现在任何表达式或 let 之后,则会导致解析错误 + +```move= +{ + let x = 0; + use std::vector; // ERROR! + let v = vector::empty(); +} +``` + +## Naming rules + +Aliases must follow the same rules as other module members. This means that aliases to structs or +constants must start with `A` to `Z` +## 命名规则 +别名必须遵循与其他模块成员相同的规则。这意味着结构或常量的别名必须以 A 到 Z 开头 + +```move= +address 0x42 { +module data { + struct S {} + const FLAG: bool = false; + fun foo() {} +} +module example { + use 0x42::data::{ + S as s, // ERROR! + FLAG as fLAG, // ERROR! + foo as FOO, // valid + foo as bar, // valid + }; +} +} +``` + +## Uniqueness + +Inside a given scope, all aliases introduced by `use` declarations must be unique. + +For a module, this means aliases introduced by `use` cannot overla +## 独特性 +在给定范围内,所有由 use 声明引入的别名必须是唯一的。 + +对于一个模块,这意味着使用引入的别名不能重叠 + +```move= +address 0x42 { +module example { + + use std::vector::{empty as foo, length as foo}; // ERROR! + // ^^^ duplicate 'foo' + + use std::vector::empty as bar; + + use std::vector::length as bar; // ERROR! + // ^^^ duplicate 'bar' + +} +} +``` + +And, they cannot overlap with any of the module's other members + +而且,它们不能与模块的任何其他成员重叠 + +```move= +address 0x42 { +module data { + struct S {} +} +module example { + use 0x42::data::S; + + struct S { value: u64 } // ERROR! + // ^ conflicts with alias 'S' above +} +} +``` + +Inside of an expression block, they cannot overlap with each other, but they can +[shadow](#shadowing) other aliases or names from an outer scope + +在表达式块内部,它们不能相互重叠,但它们可以遮蔽外部作用域中的其他别名或名称 + +## Shadowing + +`use` aliases inside of an expression block can shadow names (module members or aliases) from the +outer scope. As with shadowing of locals, the shadowing ends at the end of the expression block; +## 隐藏 + +在表达式块内使用别名可以隐藏外部范围的名称(模块成员或别名)。与局部变量的隐藏一样,阴影在表达式块的末尾结束; + +```move= +address 0x42 { +module example { + + struct WrappedVector { vec: vector } + + fun empty(): WrappedVector { + WrappedVector { vec: std::vector::empty() } + } + + fun example1(): (WrappedVector, WrappedVector) { + let vec = { + use std::vector::{empty, push_back}; + // 'empty' now refers to std::vector::empty + + let v = empty(); + push_back(&mut v, 0); + push_back(&mut v, 1); + push_back(&mut v, 10); + v + }; + // 'empty' now refers to Self::empty + + (empty(), WrappedVector { vec }) + } + + fun example2(): (WrappedVector, WrappedVector) { + use std::vector::{empty, push_back}; + let w: WrappedVector = { + use 0x42::example::empty; + empty() + }; + push_back(&mut w.vec, 0); + push_back(&mut w.vec, 1); + push_back(&mut w.vec, 10); + + let vec = empty(); + push_back(&mut vec, 0); + push_back(&mut vec, 1); + push_back(&mut vec, 10); + + (w, WrappedVector { vec }) + } +} +} +``` + +## Unused Use or Alias + +An unused `use` will result in an error + +## 未使用的使用或别名 +未使用会导致错误 + +```move= +address 0x42 { +module example { + use std::vector::{empty, push_back}; // ERROR! + // ^^^^^^^^^ unused alias 'push_back' + + fun example(): vector { + empty() + } +} +} +``` diff --git a/language/documentation/book/translations/move-book-zh/src/variables.md b/language/documentation/book/translations/move-book-zh/src/variables.md new file mode 100644 index 0000000000..805128e13d --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/variables.md @@ -0,0 +1,875 @@ +# Local Variables and Scope + +Local variables in Move are lexically (statically) scoped. New variables are introduced with the +keyword `let`, which will shadow any previous local with the same name. Locals are mutable and can +be updated both directly and via a mutable reference. +# 局部变量和范围 +Move 中的局部变量是词法(静态)范围的。使用关键字 let 引入了新变量,这将隐藏任何以前的同名本地变量。局部变量是可变的,可以直接更新,也可以通过可变引用更新。 + +## Declaring Local Variables + +### `let` bindings + +Move programs use `let` to bind variable names to values: +## 声明局部变量 +### `let` 绑定 +移动程序使用 let 将变量名绑定到值: + +```move +let x = 1; +let y = x + x: +``` + +`let` can also be used without binding a value to the local. + +let 也可以在不将值绑定到本地的情况下使用。 + +```move +let x; +``` + +The local can then be assigned a value later. + +然后可以稍后为本地分配一个值。 + +```move +let x; +if (cond) { + x = 1 +} else { + x = 0 +} +``` + +This can be very helpful when trying to extract a value from a loop when a default value cannot be +provided. + +当无法提供默认值时,这在尝试从循环中提取值时非常有用。 + +```move +let x; +let cond = true; +let i = 0; +loop { + (x, cond) = foo(i); + if (!cond) break; + i = i + 1; +} +``` + +### Variables must be assigned before use + +Move's type system prevents a local variable from being used before it has been assigned. +### 变量必须在使用前赋值 +Move 的类型系统防止在分配之前使用局部变量。 + +```move +let x; +x + x // ERROR! +``` + +```move +let x; +if (cond) x = 0; +x + x // ERROR! +``` + +```move +let x; +while (cond) x = 0; +x + x // ERROR! +``` + +### Valid variable names + +Variable names can contain underscores `_`, letters `a` to `z`, letters `A` to `Z`, and digits `0` +to `9`. Variable names must start with either an underscore `_` or a letter `a` through `z`. They +_cannot_ start with uppercase letters. +### 有效的变量名 +变量名称可以包含下划线 `_`、字母 a 到 z、字母 A 到 Z 以及数字 0 到 9。变量名称必须以下划线 `_` 或字母 a 到 z 开头。它们不能以大写字母开头。 + +```move +// all valid +let x = e; +let _x = e; +let _A = e; +let x0 = e; +let xA = e; +let foobar_123 = e; + +// all invalid +let X = e; // ERROR! +let Foo = e; // ERROR! +``` + +### Type annotations + +The type of a local variable can almost always be inferred by Move's type system. However, Move +allows explicit type annotations that can be useful for readability, clarity, or debuggability. The +syntax for adding a type annotation is: +### 类型注释 +局部变量的类型几乎总是可以通过 Move 的类型系统推断出来。但是,Move 允许显式类型注释,这对可读性、清晰性或可调试性很有用。添加类型注释的语法是: + +```move +let x: T = e; // "Variable x of type T is initialized to expression e" +``` + +Some examples of explicit type annotations: + +显式类型注释的一些示例: + +```move= +address 0x42 { +module example { + + struct S { f: u64, g: u64 } + + fun annotated() { + let u: u8 = 0; + let b: vector = b"hello"; + let a: address = @0x0; + let (x, y): (&u64, &mut u64) = (&0, &mut 1); + let S { f, g: f2 }: S = S { f: 0, g: 1 }; + } +} +} +``` + +Note that the type annotations must always be to the right of the pattern: + +请注意,类型注释必须始终位于模式的右侧: + +```move +let (x: &u64, y: &mut u64) = (&0, &mut 1); // ERROR! should be let (x, y): ... = +``` + +### When annotations are necessary + +In some cases, a local type annotation is required if the type system cannot infer the type. This +commonly occurs when the type argument for a generic type cannot be inferred. For example: +### 需要注释时 +在某些情况下,如果类型系统无法推断类型,则需要本地类型注释。当无法推断泛型类型的类型参数时,通常会发生这种情况。例如: + +```move +let _v1 = vector::empty(); // ERROR! +// ^^^^^^^^^^^^^^^ Could not infer this type. Try adding an annotation +let v2: vector = vector::empty(); // no error +``` + +In a rarer case, the type system might not be able to infer a type for divergent code (where all the +following code is unreachable). Both `return` and [`abort`](./abort-and-assert.md) are expressions +and can have any type. A [`loop`](./loops.md) has type `()` if it has a `break`, but if there is no +break out of the `loop`, it could have any type. If these types cannot be inferred, a type +annotation is required. For example, this code: + +在极少数情况下,类型系统可能无法推断不同代码的类型(以下所有代码都无法访问)。 return 和 abort 都是表达式,可以有任何类型。如果循环有中断,则其类型为 (),但如果循环没有中断,则它可以具有任何类型。如果无法推断出这些类型,则需要类型注释。例如,这段代码: + +```move +let a: u8 = return (); +let b: bool = abort 0; +let c: signer = loop (); + +let x = return (); // ERROR! +// ^ Could not infer this type. Try adding an annotation +let y = abort 0; // ERROR! +// ^ Could not infer this type. Try adding an annotation +let z = loop (); // ERROR! +// ^ Could not infer this type. Try adding an annotation +``` + +Adding type annotations to this code will expose other errors about dead code or unused local +variables, but the example is still helpful for understanding this problem. + +在这段代码中添加类型注释会暴露其他关于死代码或未使用的局部变量的错误,但该示例仍然有助于理解这个问题。 + +### Multiple declarations with tuples + +`let` can introduce more than one local at a time using tuples. The locals declared inside the +parenthesis are initialized to the corresponding values from the tuple. +### 带有元组的多个声明 +let 可以使用元组一次引入多个本地。括号内声明的局部变量被初始化为元组中的相应值。 + +```move +let () = (); +let (x0, x1) = (0, 1); +let (y0, y1, y2) = (0, 1, 2); +let (z0, z1, z2, z3) = (0, 1, 2, 3); +``` + +The type of the expression must match the arity of the tuple pattern exactly. + +表达式的类型必须与元组模式的数量完全匹配。 + +```move +let (x, y) = (0, 1, 2); // ERROR! +let (x, y, z, q) = (0, 1, 2); // ERROR! +``` + +You cannot declare more than one local with the same name in a single `let`. +您不能在一个 let 中声明多个具有相同名称的本地。 + +```move +let (x, x) = 0; // ERROR! +``` + +### Multiple declarations with structs + +`let` can also introduce more than one local at a time when destructuring (or matching against) a +struct. In this form, the `let` creates a set of local variables that are initialized to the values +of the fields from a struct. The syntax looks like this: +### 带有结构的多个声明 +let 还可以在解构(或匹配)结构时一次引入多个本地。在这种形式中,let 创建了一组局部变量,这些变量被初始化为结构中字段的值。语法如下所示: + +```move +struct T { f1: u64, f2: u64 } +``` + +```move +let T { f1: local1, f2: local2 } = T { f1: 1, f2: 2 }; +// local1: u64 +// local2: u64 +``` + +Here is a more complicated example: + +这是一个更复杂的例子: + +```move +address 0x42 { +module example { + struct X { f: u64 } + struct Y { x1: X, x2: X } + + fun new_x(): X { + X { f: 1 } + } + + fun example() { + let Y { x1: X { f }, x2 } = Y { x1: new_x(), x2: new_x() }; + assert!(f + x2.f == 2, 42); + + let Y { x1: X { f: f1 }, x2: X { f: f2 } } = Y { x1: new_x(), x2: new_x() }; + assert!(f1 + f2 == 2, 42); + } +} +} +``` + +Fields of structs can serve double duty, identifying the field to bind _and_ the name of the +variable. This is sometimes referred to as punning. +结构的字段可以起到双重作用,识别要绑定的字段和变量的名称。这有时被称为双关语。 + +```move +let X { f } = e; +``` + +is equivalent to: + +相当于: + +```move +let X { f: f } = e; +``` + +As shown with tuples, you cannot declare more than one local with the same name in a single `let`. + +如元组所示,您不能在单个 let 中声明多个具有相同名称的本地。 + +```move +let Y { x1: x, x2: x } = e; // ERROR! +``` + +### Destructuring against references + +In the examples above for structs, the bound value in the let was moved, destroying the struct value +and binding its fields. +### 针对引用进行解构 +在上面的结构示例中,let 中的绑定值被移动,破坏了结构值并绑定了它的字段。 + +```move +struct T { f1: u64, f2: u64 } +``` + +```move +let T { f1: local1, f2: local2 } = T { f1: 1, f2: 2 }; +// local1: u64 +// local2: u64 +``` + +In this scenario the struct value `T { f1: 1, f2: 2 }` no longer exists after the `let`. + +If you wish instead to not move and destroy the struct value, you can borrow each of its fields. For +example: +在这种情况下,结构值 T { f1: 1, f2: 2 } 在 let 之后不再存在。 + +如果您希望不移动和破坏结构值,则可以借用其每个字段。例如: + +```move +let t = T { f1: 1, f2: 2 }; +let T { f1: local1, f2: local2 } = &t; +// local1: &u64 +// local2: &u64 +``` + +And similarly with mutable references: +与可变引用类似: + +```move +let t = T { f1: 1, f2: 2 }; +let T { f1: local1, f2: local2 } = &mut t; +// local1: &mut u64 +// local2: &mut u64 +``` + +This behavior can also work with nested structs. +此行为也适用于嵌套结构。 + +```move +address 0x42 { +module example { + struct X { f: u64 } + struct Y { x1: X, x2: X } + + fun new_x(): X { + X { f: 1 } + } + + fun example() { + let y = Y { x1: new_x(), x2: new_x() }; + + let Y { x1: X { f }, x2 } = &y; + assert!(*f + x2.f == 2, 42); + + let Y { x1: X { f: f1 }, x2: X { f: f2 } } = &mut y; + *f1 = *f1 + 1; + *f2 = *f2 + 1; + assert!(*f1 + *f2 == 4, 42); + } +} +} +``` + +### Ignoring Values + +In `let` bindings, it is often helpful to ignore some values. Local variables that start with `_` +will be ignored and not introduce a new variable +### 忽略值 +在 let 绑定中,忽略某些值通常很有帮助。以 _ 开头的局部变量将被忽略,不会引入新变量 + +```move +fun three(): (u64, u64, u64) { + (0, 1, 2) +} +``` + +```move +let (x1, _, z1) = three(); +let (x2, _y, z2) = three(); +assert!(x1 + z1 == x2 + z2) +``` + +This can be necessary at times as the compiler will error on unused local variables +这有时是必要的,因为编译器会在未使用的局部变量上出错 + +```move +let (x1, y, z1) = three(); // ERROR! +// ^ unused local 'y' +``` + +### General `let` grammar + +All of the different structures in `let` can be combined! With that we arrive at this general +grammar for `let` statements: +### 一般 `let` 语法 +let 中所有不同的结构都可以组合!这样,我们就得出了 let 语句的一般语法: + +> _let-binding_ → **let** _pattern-or-list_ _type-annotation__opt_ +> _initializer__opt_ > _pattern-or-list_ → _pattern_ | **(** _pattern-list_ **)** > +> _pattern-list_ → _pattern_ **,**_opt_ | _pattern_ **,** _pattern-list_ > +> _type-annotation_ → **:** _type_ _initializer_ → **=** _expression_ + +The general term for the item that introduces the bindings is a _pattern_. The pattern serves to +both destructure data (possibly recursively) and introduce the bindings. The pattern grammar is as +follows: + +引入绑定的项目的通用术语是模式。该模式用于解构数据(可能是递归的)并引入绑定。模式语法如下: + +> _pattern_ → _local-variable_ | _struct-type_ **{** _field-binding-list_ **}** > +> _field-binding-list_ → _field-binding_ **,**_opt_ | _field-binding_ **,** +> _field-binding-list_ > _field-binding_ → _field_ | _field_ **:** _pattern_ + +A few concrete examples with this grammar applied: + +应用此语法的一些具体示例: + +```move + let (x, y): (u64, u64) = (0, 1); +// ^ local-variable +// ^ pattern +// ^ local-variable +// ^ pattern +// ^ pattern-list +// ^^^^ pattern-list +// ^^^^^^ pattern-or-list +// ^^^^^^^^^^^^ type-annotation +// ^^^^^^^^ initializer +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ let-binding + + let Foo { f, g: x } = Foo { f: 0, g: 1 }; +// ^^^ struct-type +// ^ field +// ^ field-binding +// ^ field +// ^ local-variable +// ^ pattern +// ^^^^ field-binding +// ^^^^^^^ field-binding-list +// ^^^^^^^^^^^^^^^ pattern +// ^^^^^^^^^^^^^^^ pattern-or-list +// ^^^^^^^^^^^^^^^^^^^^ initializer +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ let-binding +``` + +## Mutations + +### Assignments + +After the local is introduced (either by `let` or as a function parameter), the local can be +modified via an assignment: +## 突变 +### 作业 +在引入局部后(通过 let 或作为函数参数),可以通过赋值来修改局部: + +```move +x = e +``` + +Unlike `let` bindings, assignments are expressions. In some languages, assignments return the value +that was assigned, but in Move, the type of any assignment is always `()`. + +与 let 绑定不同,赋值是表达式。在某些语言中,赋值返回被赋值的值,但在 Move 中,任何赋值的类型始终是 ()。 + +```move +(x = e: ()) +``` + +Practically, assignments being expressions means that they can be used without adding a new +expression block with braces (`{`...`}`). +实际上,赋值是表达式意味着它们可以在不添加带有大括号 ({...}) 的新表达式块的情况下使用。 + +```move +let x = 0; +if (cond) x = 1 else x = 2; +``` + +The assignment uses the same pattern syntax scheme as `let` bindings: + +赋值使用与 let 绑定相同的模式语法方案: + +```move= +address 0x42 { +module example { + struct X { f: u64 } + + fun new_x(): X { + X { f: 1 } + } + + // This example will complain about unused variables and assignments. + fun example() { + let (x, _, z) = (0, 1, 3); + let (x, y, f, g); + + (X { f }, X { f: x }) = (new_x(), new_x()); + assert!(f + x == 2, 42); + + (x, y, z, f, _, g) = (0, 0, 0, 0, 0, 0); + } +} +} +``` + +Note that a local variable can only have one type, so the type of the local cannot change between +assignments. +注意一个局部变量只能有一种类型,所以局部变量的类型不能在赋值之间改变。 + +```move +let x; +x = 0; +x = false; // ERROR! +``` + +### Mutating through a reference + +In addition to directly modifying a local with assignment, a local can be modified via a mutable +reference `&mut`. +### 通过引用进行变异 +除了通过赋值直接修改局部外,还可以通过可变引用 &mut 修改局部。 + +```move +let x = 0; +let r = &mut x; +*r = 1; +assert!(x == 1, 42) +} +``` + +This is particularly useful if either: + +(1) You want to modify different variables depending on some condition. + +这在以下情况下特别有用: + +(1) 您想根据某些条件修改不同的变量。 + +```move +let x = 0; +let y = 1; +let r = if (cond) &mut x else &mut y; +*r = *r + 1; +``` + +(2) You want another function to modify your local value. + +(2) 你想要另一个函数来修改你的本地值。 + +```move +let x = 0; +modify_ref(&mut x); +``` + +This sort of modification is how you modify structs and vectors! + +这种修改就是你修改结构和向量的方式! + +```move +let v = vector::empty(); +vector::push_back(&mut v, 100); +assert!(*vector::borrow(&v, 0) == 100, 42) +``` + +For more details, see [Move references](./references.md). + +有关更多详细信息,请参阅移动引用。 + +## Scopes + +Any local declared with `let` is available for any subsequent expression, _within that scope_. +Scopes are declared with expression blocks, `{`...`}`. + +Locals cannot be used outside of the declared scope. +## 范围 +使用 let 声明的任何本地表达式都可用于该范围内的任何后续表达式。范围用表达式块声明,{...}。 + +局部变量不能在声明的范围之外使用。 + +```move +let x = 0; +{ + let y = 1; +}; +x + y // ERROR! +// ^ unbound local 'y' +``` + +But, locals from an outer scope _can_ be used in a nested scope. + +但是,来自外部作用域的本地变量可以在嵌套作用域中使用。 + +```move +{ + let x = 0; + { + let y = x + 1; // valid + } +} +``` + +Locals can be mutated in any scope where they are accessible. That mutation survives with the local, +regardless of the scope that performed the mutation. + +局部变量可以在可以访问的任何范围内进行变异。无论执行突变的范围如何,该突变都会在本地生存。 + +```move +let x = 0; +x = x + 1; +assert!(x == 1, 42); +{ + x = x + 1; + assert!(x == 2, 42); +}; +assert!(x == 2, 42); +``` + +### Expression Blocks + +An expression block is a series of statements separated by semicolons (`;`). The resulting value of +an expression block is the value of the last expression in the block. +### 表达式块 +表达式块是由分号 (;) 分隔的一系列语句。表达式块的结果值是块中最后一个表达式的值。 + +```move +{ let x = 1; let y = 1; x + y } +``` + +In this example, the result of the block is `x + y`. + +A statement can be either a `let` declaration or an expression. Remember that assignments (`x = e`) +are expressions of type `()`. + +在此示例中,块的结果是 x + y。 + +语句可以是 let 声明或表达式。请记住,赋值 (x = e) 是 () 类型的表达式。 + +```move +{ let x; let y = 1; x = 1; x + y } +``` + +Function calls are another common expression of type `()`. Function calls that modify data are +commonly used as statements. + +函数调用是类型 () 的另一种常见表达方式。修改数据的函数调用通常用作语句。 + +```move +{ let v = vector::empty(); vector::push_back(&mut v, 1); v } +``` + +This is not just limited to `()` types---any expression can be used as a statement in a sequence! + +这不仅限于 () 类型——任何表达式都可以用作序列中的语句! + +```move +{ + let x = 0; + x + 1; // value is discarded + x + 2; // value is discarded + b"hello"; // value is discarded +} +``` + +But! If the expression contains a resource (a value without the `drop` [ability](./abilities.md)), +you will get an error. This is because Move's type system guarantees that any value that is dropped +has the `drop` [ability](./abilities.md). (Ownership must be transferred or the value must be +explicitly destroyed within its declaring module.) + +但!如果表达式包含资源(没有丢弃能力的值),您将收到错误消息。这是因为 Move 的类型系统保证任何被删除的值都具有删除能力。 (必须转移所有权,或者必须在其声明模块中显式销毁该值。) + +```move +{ + let x = 0; + Coin { value: x }; // ERROR! +// ^^^^^^^^^^^^^^^^^ unused value without the `drop` ability + x +} +``` + +If a final expression is not present in a block---that is, if there is a trailing semicolon `;`, +there is an implicit unit `()` value. Similarly, if the expression block is empty, there is an +implicit unit `()` value. + +如果块中不存在最终表达式——也就是说,如果有一个尾随分号;,则有一个隐含的 unit () 值。同样,如果表达式块为空,则存在隐含的 unit() 值。 + +```move +// Both are equivalent +// 两者是等价的 +{ x = x + 1; 1 / x; } +{ x = x + 1; 1 / x; () } +``` + +```move +// Both are equivalent +{ } +{ () } +``` + +An expression block is itself an expression and can be used anyplace an expression is used. (Note: +The body of a function is also an expression block, but the function body cannot be replaced by +another expression.) +表达式块本身就是一个表达式,可以在任何使用表达式的地方使用。 (注意:函数体也是一个表达式块,但函数体不能被另一个表达式代替。) + +```move +let my_vector: vector> = { + let v = vector::empty(); + vector::push_back(&mut v, b"hello"); + vector::push_back(&mut v, b"goodbye"); + v +}; +``` + +(The type annotation is not needed in this example and only added for clarity.) +(此示例中不需要类型注释,只是为了清楚起见而添加。) + +### Shadowing + +If a `let` introduces a local variable with a name already in scope, that previous variable can no +longer be accessed for the rest of this scope. This is called _shadowing_. + +### 隐藏 +如果一个 let 引入了一个名称已经在作用域中的局部变量,则该作用域的其余部分将无法再访问先前的变量。这称为隐藏。 + +```move +let x = 0; +assert!(x == 0, 42); + +let x = 1; // x is shadowed +assert!(x == 1, 42); +``` + +When a local is shadowed, it does not need to retain the same type as before. + +当局部被遮蔽时,它不需要保留与以前相同的类型。 + +```move +let x = 0; +assert!(x == 0, 42); + +let x = b"hello"; // x is shadowed +assert!(x == b"hello", 42); +``` + +After a local is shadowed, the value stored in the local still exists, but will no longer be +accessible. This is important to keep in mind with values of types without the +[`drop` ability](./abilities.md), as ownership of the value must be transferred by the end of the +function. + +在本地被遮蔽后,存储在本地的值仍然存在,但将不再可访问。对于没有删除能力的类型的值,请记住这一点很重要,因为值的所有权必须在函数结束时转移。 + +```move +address 0x42 { + module example { + struct Coin has store { value: u64 } + + fun unused_resource(): Coin { + let x = Coin { value: 0 }; // ERROR! +// ^ This local still contains a value without the `drop` ability + x.value = 1; + let x = Coin { value: 10 }; + x +// ^ Invalid return + } + } +} +``` + +When a local is shadowed inside a scope, the shadowing only remains for that scope. The shadowing is +gone once that scope ends. +当本地在范围内被遮蔽时,该遮蔽仅保留在该范围内。一旦该范围结束,阴影就消失了。 + +```move +let x = 0; +{ + let x = 1; + assert!(x == 1, 42); +}; +assert!(x == 0, 42); +``` + +Remember, locals can change type when they are shadowed. + +请记住,本地人在被遮蔽时可以更改类型。 + +```move +let x = 0; +{ + let x = b"hello"; + assert!(x = b"hello", 42); +}; +assert!(x == 0, 42); +``` + +## Move and Copy + +All local variables in Move can be used in two ways, either by `move` or `copy`. If one or the other +is not specified, the Move compiler is able to infer whether a `copy` or a `move` should be used. +This means that in all of the examples above, a `move` or a `copy` would be inserted by the +compiler. A local variable cannot be used without the use of `move` or `copy`. + +`copy` will likely feel the most familiar coming from other programming languages, as it creates a +new copy of the value inside of the variable to use in that expression. With `copy`, the local +variable can be used more than once. +## 移动和复制 +Move 中的所有局部变量都可以通过两种方式使用,通过移动或复制。如果未指定其中之一,则 Move 编译器能够推断应该使用副本还是移动。这意味着在上述所有示例中,编译器将插入移动或复制。如果不使用移动或复制,就不能使用局部变量。 + +复制可能会让人感觉最熟悉来自其他编程语言,因为它会在变量内部创建一个新的值副本以在该表达式中使用。使用复制,可以多次使用局部变量。 + +```move +let x = 0; +let y = copy x + 1; +let z = copy x + 2; +``` + +Any value with the `copy` [ability](./abilities.md) can be copied in this way. + +`move` takes the value out of the local variable _without_ copying the data. After a `move` occurs, +the local variable is unavailable. + +任何具有复制能力的值都可以通过这种方式复制。 + +move 从局部变量中取出值而不复制数据。移动发生后,局部变量不可用。 + +```move +let x = 1; +let y = move x + 1; +// ------ Local was moved here +let z = move x + 2; // Error! +// ^^^^^^ Invalid usage of local 'x' +y + z +``` + +### Safety + +Move's type system will prevent a value from being used after it is moved. This is the same safety +check described in [`let` declaration](#let-bindings) that prevents local variables from being used +before it is assigned a value. +### 安全 +Move 的类型系统会阻止一个值在移动后被使用。这与 let 声明中描述的安全检查相同,可防止在为其赋值之前使用局部变量。 + + + +### Inference + +As mentioned above, the Move compiler will infer a `copy` or `move` if one is not indicated. The +algorithm for doing so is quite simple: + +- Any scalar value with the `copy` [ability](./abilities.md) is given a `copy`. +- Any reference (both mutable `&mut` and immutable `&`) is given a `copy`. + - Except under special circumstances where it is made a `move` for predictable borrow checker + errors. +- Any other value is given a `move`. + - This means that even though other values might be have the `copy` [ability](./abilities.md), it + must be done _explicitly_ by the programmer. + - This is to prevent accidental copies of large data structures. + +For example: +### 推理 +如上所述,如果未指明,Move 编译器将推断出副本或移动。这样做的算法非常简单: + +- 任何具有复制能力的标量值都会被赋予一个副本。 +- 任何引用(可变的 &mut 和不可变的 &)都会给出一个副本。 + - 除非在特殊情况下会因可预测的借用检查器错误而采取行动。 +- 任何其他值都会被移动。 + - 这意味着即使其他值可能具有复制能力,也必须由程序员明确完成。 + - 这是为了防止意外复制大型数据结构。 +例如: + +```move +let s = b"hello"; +let foo = Foo { f: 0 }; +let coin = Coin { value: 0 }; + +let s2 = s; // move +let foo2 = foo; // move +let coin2 = coin; // move + +let x = 0; +let b = false; +let addr = @0x42; +let x_ref = &x; +let coin_ref = &mut coin2; + +let x2 = x; // copy +let b2 = b; // copy +let addr2 = @0x42; // copy +let x_ref2 = x_ref; // copy +let coin_ref2 = coin_ref; // copy +``` diff --git a/language/documentation/book/translations/move-book-zh/src/vector.md b/language/documentation/book/translations/move-book-zh/src/vector.md new file mode 100644 index 0000000000..6a4ce86798 --- /dev/null +++ b/language/documentation/book/translations/move-book-zh/src/vector.md @@ -0,0 +1,209 @@ +# Vector + +`vector` is the only primitive collection type provided by Move. A `vector` is a homogenous +collection of `T`'s that can grow or shrink by pushing/popping values off the "end". + +A `vector` can be instantiated with any type `T`. For example, `vector`, `vector
`, +`vector<0x42::MyModule::MyResource>`, and `vector>` are all valid vector types. +# 向量 +矢量 T 是 Move 提供的唯一原始集合类型。向量 T 是 T 的同质集合,可以通过从“末端”推/弹出值来增长或缩小。 + +向量 T 可以用任何类型 T 实例化。例如,向量 u64 、向量地址 、向量 0x42::MyModule::MyResource 和向量向量 u8 都是有效的向量类型。 + +## Literals + +### General `vector` Literals + +Vectors of any type can be created with `vector` literals. +## 字面量 +### 一般向量字面量 +任何类型的向量都可以用向量字面量创建。 + +| Syntax | Type | Description | +| --------------------- | ----------------------------------------------------------------------------- | ------------------------------------------ | +| `vector[]` | `vector[]: vector` where `T` is any single, non-reference type | An empty vector | +| `vector[e1, ..., en]` | `vector[e1, ..., en]: vector` where `e_i: T` s.t. `0 < i <= n` and `n > 0` | A vector with `n` elements (of length `n`) | + +In these cases, the type of the `vector` is inferred, either from the element type or from the +vector's usage. If the type cannot be inferred, or simply for added clarity, the type can be +specified explicitly: +在这些情况下,向量的类型是根据元素类型或向量的使用来推断的。如果无法推断类型,或者只是为了更清楚起见,可以显式指定类型: + +```move +vector[]: vector +vector[e1, ..., en]: vector +``` + +#### Example Vector Literals +#### 示例向量文字 + +```move +(vector[]: vector); +(vector[0u8, 1u8, 2u8]: vector); +(vector[]: vector); +(vector
[@0x42, @0x100]: vector
); +``` + +### `vector` literals + +A common use-case for vectors in Move is to represent "byte arrays", which are represented with +`vector`. These values are often used for cryptographic purposes, such as a public key or a hash +result. These values are so common that specific syntax is provided to make the values more +readable, as opposed to having to use `vector[]` where each individual `u8` value is specified in +numeric form. + +There are currently two supported types of `vector` literals, byte strings and hex strings. +### 矢量 u8 字面量 +Move 中向量的一个常见用例是表示“字节数组”,用向量 u8 表示。这些值通常用于加密目的,例如公钥或哈希结果。这些值非常常见,以至于提供了特定的语法以使值更具可读性,而不是必须使用 vector[] ,其中每个单独的 u8 值都以数字形式指定。 + +目前有两种受支持的向量 u8 文字类型,字节字符串和十六进制字符串。 + +#### Byte Strings + +Byte strings are quoted string literals prefixed by a `b`, e.g. `b"Hello!\n"`. + +These are ASCII encoded strings that allow for escape sequences. Currently, the supported escape +sequences are +#### 字节串 +字节字符串是以 a b 为前缀的带引号的字符串文字,例如b“你好!”。 + +这些是允许转义序列的 ASCII 编码字符串。目前,支持的转义序列是 + +| Escape Sequence | Description | +| --------------- | ---------------------------------------------- | +| `\n` | New line (or Line feed) | +| `\r` | Carriage return | +| `\t` | Tab | +| `\\` | Backslash | +| `\0` | Null | +| `\"` | Quote | +| `\xHH` | Hex escape, inserts the hex byte sequence `HH` | + +#### Hex Strings + +Hex strings are quoted string literals prefixed by a `x`, e.g. `x"48656C6C6F210A"` + +Each byte pair, ranging from `00` to `FF`, is interpreted as hex encoded `u8` value. So each byte +pair corresponds to a single entry in the resulting `vector` +#### 十六进制字符串 +十六进制字符串是以 x 为前缀的带引号的字符串文字,例如x'48656C6C6F210A' + +每个字节对,范围从 00 到 FF,都被解释为十六进制编码的 u8 值。所以每个字节对对应于结果向量 u8 中的一个条目 + +#### Example String Literals + +```move +script { +fun byte_and_hex_strings() { + assert!(b"" == x"", 0); + assert!(b"Hello!\n" == x"48656C6C6F210A", 1); + assert!(b"\x48\x65\x6C\x6C\x6F\x21\x0A" == x"48656C6C6F210A", 2); + assert!( + b"\"Hello\tworld!\"\n \r \\Null=\0" == + x"2248656C6C6F09776F726C6421220A200D205C4E756C6C3D00", + 3 + ); +} +} +``` + +## Operations + +`vector` supports the following operations via the `std::vector` module in the Move standard +library: +## 操作符 +vector 通过 Move 标准库中的 std::vector 模块支持以下操作: + +| Function | Description | Aborts? | +| ---------------------------------------------------------- | ------------------------------------------------------------- | ----------------------- | +| `vector::empty(): vector` | Create an empty vector that can store values of type `T` | Never | +| `vector::singleton(t: T): vector` | Create a vector of size 1 containing `t` | Never | +| `vector::push_back(v: &mut vector, t: T)` | Add `t` to the end of `v` | Never | +| `vector::pop_back(v: &mut vector): T` | Remove and return the last element in `v` | If `v` is empty | +| `vector::borrow(v: &vector, i: u64): &T` | Return an immutable reference to the `T` at index `i` | If `i` is not in bounds | +| `vector::borrow_mut(v: &mut vector, i: u64): &mut T` | Return an mutable reference to the `T` at index `i` | If `i` is not in bounds | +| `vector::destroy_empty(v: vector)` | Delete `v` | If `v` is not empty | +| `vector::append(v1: &mut vector, v2: vector)` | Add the elements in `v2` to the end of `v1` | If `i` is not in bounds | +| `vector::contains(v: &vector, e: &T): bool` | Return true if `e` is in the vector `v` | Never | +| `vector::swap(v: &mut vector, i: u64, j: u64)` | Swaps the elements at the `i`th and `j`th indices in the vector `v`.| If `i` or `j` is out of bounds | +| `vector::reverse(v: &mut vector)` | Reverses the order of the elements in the vector `v` in place | Never | +| `vector::index_of(v: &vector, e: &T): bool` | Return `(true, i)` if `e` is in the vector `v` at index `i`. Otherwise, returns `(false, 0)`.| Never | +| `vector::remove(v: &mut vector, i: u64): T` | Remove the `i`th element of the vector `v`, shifting all subsequent elements. This is O(n) and preserves ordering of elements in the vector. | If `i` is out of bounds. | +| `vector::swap_remove(v: &mut vector, i: u64): T` | Swap the `i`th element of the vector `v` with the last element and then pop the vector, This is O(1), but does not preserve ordering of elements in the vector. | If `i` is out of bounds. | + +More operations may be added overtime + +更多操作可能会加班 + +## Example +## 例子 + +```move +use std::vector; + +let v = vector::empty(); +vector::push_back(&mut v, 5); +vector::push_back(&mut v, 6); + +assert!(*vector::borrow(&v, 0) == 5, 42); +assert!(*vector::borrow(&v, 1) == 6, 42); +assert!(vector::pop_back(&mut v) == 6, 42); +assert!(vector::pop_back(&mut v) == 5, 42); +``` + +## Destroying and copying `vector`s + +Some behaviors of `vector` depend on the abilities of the element type, `T`. For example, vectors +containing elements that do not have `drop` cannot be implicitly discarded like `v` in the example +above--they must be explicitly destroyed with `vector::destroy_empty`. + +Note that `vector::destroy_empty` will abort at runtime unless `vec` contains zero elements: +## 销毁和复制向量 +向量 T 的某些行为取决于元素类型 T 的能力。例如,包含不具有 drop 的元素的向量不能像上例中的 v 那样被隐式丢弃——它们必须用 vector::destroy_empty 显式销毁。 + +请注意,除非 vec 包含零个元素,否则 vector::destroy_empty 将在运行时中止: + +```move +fun destroy_any_vector(vec: vector) { + vector::destroy_empty(vec) // deleting this line will cause a compiler error +} +``` + +But no error would occur for dropping a vector that contains elements with `drop`: + +但是删除包含带有 drop 的元素的向量不会发生错误: + +```move +fun destroy_droppable_vector(vec: vector) { + // valid! + // nothing needs to be done explicitly to destroy the vector +} +``` + +Similarly, vectors cannot be copied unless the element type has `copy`. In other words, a +`vector` has `copy` if and only if `T` has `copy`. However, even copyable vectors are never +implicitly copied: + +同样,除非元素类型具有副本,否则无法复制向量。换句话说,一个向量 T 有副本当且仅当 T 有副本。然而,即使是可复制的向量也永远不会被隐式复制: + +```move +let x = vector::singleton(10); +let y = copy x; // compiler error without the copy! +``` + +Copies of large vectors can be expensive, so the compiler requires explicit `copy`'s to make it +easier to see where they are happening. + +For more details see the sections on [type abilities](./abilities.md) and [generics](./generics.md). + +大向量的副本可能很昂贵,因此编译器需要显式副本以便更容易查看它们发生的位置。 + +有关更多详细信息,请参阅类型能力和泛型部分。 + +## Ownership + +As mentioned [above](#destroying-and-copying-vectors), `vector` values can be copied only if the +elements can be copied. In that case, the copy must be explicit via a +[`copy`](./variables.md#move-and-copy) or a [dereference `*`](./references.md#reference-operators). +## 所有权 +如上所述,只有可以复制元素,才能复制向量值。在这种情况下,副本必须通过副本或取消引用 * 显式。 From 76c11e3845bc3a8930ea0d860a62d986eec25ba2 Mon Sep 17 00:00:00 2001 From: Wolfgang Grieskamp Date: Mon, 8 Aug 2022 21:16:54 -0700 Subject: [PATCH 049/169] [packages] New dependency type 'node' + custom package info properties (#357) * [packages] New dependency type 'node' + custom package info properties This adds a new dependency type to the package manifest which allows to specify a node from which to receive a package: ``` [dependencies] MoveStdlib = { node: "localhost:8080", address: "0x1", package: "move-stdlib" } ``` Resolution of such kind of a dependency is handled via a new trait `PackageHooks` which can be globally registered on a per-process basis. If no hook is registered, an error will be produced that `node` deps are not supported. Note: After investigating some time whether the resolver could be passed in as a parameter, it became clear that a larger refactoring woul be needed as the package system is simply not designed for compositionality like this. In additionn to the new dependency type, this also allows additional fields in the `[package]` section, as in ``` [package] name = "Foobar" upgrade_policy = .. ``` The valid extra names are again determined by the `PackageHooks`. * [fixup] Add TODO and rename node to url * [fixup] Now actually making the name of the custom dependency customizable. So one can via the hooks determine if its `movey`, `sui`, or `aptos`. --- Cargo.lock | 1 + language/tools/move-package/Cargo.toml | 1 + language/tools/move-package/src/lib.rs | 1 + .../tools/move-package/src/package_hooks.rs | 66 ++++++++ .../src/resolution/resolution_graph.rs | 10 +- .../src/source_package/manifest_parser.rs | 141 +++++++++++++----- .../src/source_package/parsed_manifest.rs | 15 ++ .../tools/move-package/tests/test_runner.rs | 37 ++++- .../invalid_identifier_package_name/Move.exp | 2 + .../parsing/minimal_manifest/Move.exp | 2 + .../no_path_set_for_dependency/Move.exp | 2 +- .../resolution/basic_no_deps/Move.exp | 2 + .../basic_no_deps_address_assigned/Move.exp | 2 + .../Move.exp | 2 + .../resolution/dep_good_digest/Move.exp | 5 + .../Move.exp | 11 ++ .../diamond_problem_no_conflict/Move.exp | 11 ++ .../resolution/multiple_deps_rename/Move.exp | 8 + .../test_sources/resolution/one_dep/Move.exp | 5 + .../one_dep_assigned_address/Move.exp | 5 + .../one_dep_multiple_of_same_name/Move.exp | 5 + .../one_dep_reassigned_address/Move.exp | 5 + .../Move.exp | 5 + .../resolution/package_hooks/Move.exp | 1 + .../resolution/package_hooks/Move.toml | 6 + 25 files changed, 312 insertions(+), 39 deletions(-) create mode 100644 language/tools/move-package/src/package_hooks.rs create mode 100644 language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.exp create mode 100644 language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.toml diff --git a/Cargo.lock b/Cargo.lock index acb9c62c98..d065f5baa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2733,6 +2733,7 @@ dependencies = [ "dirs-next", "evm-exec-utils", "hex", + "itertools 0.10.1", "move-abigen", "move-binary-format", "move-bytecode-source-map", diff --git a/language/tools/move-package/Cargo.toml b/language/tools/move-package/Cargo.toml index 4cb647e676..601d1a854a 100644 --- a/language/tools/move-package/Cargo.toml +++ b/language/tools/move-package/Cargo.toml @@ -24,6 +24,7 @@ ptree = "0.4.0" once_cell = "1.7.2" named-lock = "0.1.1" dirs-next = "2.0.0" +itertools = "0.10.0" move-binary-format = { path = "../../move-binary-format" } move-compiler = { path = "../../move-compiler" } diff --git a/language/tools/move-package/src/lib.rs b/language/tools/move-package/src/lib.rs index 61011bb8e9..ddbe1a5d55 100644 --- a/language/tools/move-package/src/lib.rs +++ b/language/tools/move-package/src/lib.rs @@ -5,6 +5,7 @@ mod package_lock; pub mod compilation; +pub mod package_hooks; pub mod resolution; pub mod source_package; diff --git a/language/tools/move-package/src/package_hooks.rs b/language/tools/move-package/src/package_hooks.rs new file mode 100644 index 0000000000..9d6f338926 --- /dev/null +++ b/language/tools/move-package/src/package_hooks.rs @@ -0,0 +1,66 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::source_package::parsed_manifest::CustomDepInfo; +use anyhow::bail; +use move_symbol_pool::Symbol; +use once_cell::sync::Lazy; +use std::sync::Mutex; + +// TODO: remove static hooks and refactor this crate for better customizability + +/// A trait providing hooks to customize the package system for a particular Move application. +/// An instance of the trait can be registered globally. +pub trait PackageHooks { + /// Returns custom fields allowed in `PackageInfo`. + fn custom_package_info_fields(&self) -> Vec; + + /// Returns a custom key for dependencies, if available. This is the string used + /// in dependencies `{ = value, address = addr }. + fn custom_dependency_key(&self) -> Option; + + /// A resolver for custom dependencies in the manifest. This is called to download the + /// dependency from the dependency into the `info.local_path` location, similar as with git + /// dependencies. + fn resolve_custom_dependency( + &self, + dep_name: Symbol, + info: &CustomDepInfo, + ) -> anyhow::Result<()>; +} +static HOOKS: Lazy>>> = + Lazy::new(|| Mutex::new(None)); + +/// Registers package hooks for the process in which the package system is used. +pub fn register_package_hooks(hooks: Box) { + *HOOKS.lock().unwrap() = Some(hooks) +} + +/// Calls any registered hook to resolve a node dependency. Bails if none is registered. +pub(crate) fn resolve_custom_dependency( + dep_name: Symbol, + info: &CustomDepInfo, +) -> anyhow::Result<()> { + if let Some(hooks) = &*HOOKS.lock().unwrap() { + hooks.resolve_custom_dependency(dep_name, info) + } else { + bail!("use of unsupported custom dependency in package manifest") + } +} + +pub(crate) fn custom_dependency_key() -> Option { + if let Some(hooks) = &*HOOKS.lock().unwrap() { + hooks.custom_dependency_key() + } else { + None + } +} + +/// Calls any registered hook to return custom package fields. +pub(crate) fn custom_package_info_fields() -> Vec { + if let Some(hooks) = &*HOOKS.lock().unwrap() { + hooks.custom_package_info_fields() + } else { + vec![] + } +} diff --git a/language/tools/move-package/src/resolution/resolution_graph.rs b/language/tools/move-package/src/resolution/resolution_graph.rs index 295e0e948f..1ef8726583 100644 --- a/language/tools/move-package/src/resolution/resolution_graph.rs +++ b/language/tools/move-package/src/resolution/resolution_graph.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ + package_hooks, resolution::digest::compute_digest, source_package::{ layout::SourcePackageLayout, @@ -392,7 +393,7 @@ impl ResolvingGraph { dep: Dependency, root_path: PathBuf, ) -> Result<(Renaming, ResolvingTable)> { - Self::download_and_update_if_repo(dep_name_in_pkg, &dep)?; + Self::download_and_update_if_remote(dep_name_in_pkg, &dep)?; let (dep_package, dep_package_dir) = Self::parse_package_manifest(&dep, &dep_name_in_pkg, root_path) .with_context(|| format!("While processing dependency '{}'", dep_name_in_pkg))?; @@ -530,7 +531,7 @@ impl ResolvingGraph { }; for (dep_name, dep) in manifest.dependencies.iter().chain(additional_deps.iter()) { - Self::download_and_update_if_repo(*dep_name, dep)?; + Self::download_and_update_if_remote(*dep_name, dep)?; let (dep_manifest, _) = Self::parse_package_manifest(dep, dep_name, root_path.to_path_buf()) @@ -541,7 +542,7 @@ impl ResolvingGraph { Ok(()) } - fn download_and_update_if_repo(dep_name: PackageName, dep: &Dependency) -> Result<()> { + fn download_and_update_if_remote(dep_name: PackageName, dep: &Dependency) -> Result<()> { if let Some(git_info) = &dep.git_info { if !git_info.download_to.exists() { Command::new("git") @@ -571,6 +572,9 @@ impl ResolvingGraph { })?; } } + if let Some(node_info) = &dep.node_info { + package_hooks::resolve_custom_dependency(dep_name, node_info)? + } Ok(()) } } diff --git a/language/tools/move-package/src/source_package/manifest_parser.rs b/language/tools/move-package/src/source_package/manifest_parser.rs index e6139c1d67..fc81afb16b 100644 --- a/language/tools/move-package/src/source_package/manifest_parser.rs +++ b/language/tools/move-package/src/source_package/manifest_parser.rs @@ -2,7 +2,7 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::{source_package::parsed_manifest as PM, Architecture}; +use crate::{package_hooks, source_package::parsed_manifest as PM, Architecture}; use anyhow::{bail, format_err, Context, Result}; use move_command_line_common::env::MOVE_HOME; use move_core_types::account_address::{AccountAddress, AccountAddressParseError}; @@ -110,7 +110,12 @@ pub fn parse_package_info(tval: TV) -> Result { match tval { TV::Table(mut table) => { check_for_required_field_names(&table, &["name", "version"])?; - warn_if_unknown_field_names(&table, &["name", "version", "authors", "license"]); + let hook_names = package_hooks::custom_package_info_fields(); + let known_names = ["name", "version", "authors", "license"] + .into_iter() + .chain(hook_names.iter().map(|s| s.as_str())) + .collect::>(); + warn_if_unknown_field_names(&table, known_names.as_slice()); let name = table .remove("name") .ok_or_else(|| format_err!("'name' is a required field but was not found",))?; @@ -145,12 +150,22 @@ pub fn parse_package_info(tval: TV) -> Result { .collect::>()? } }; + // Turn the remaining entries into custom properties. For those which are not + // supported (also in the presence of hooks) we have warned above. + let mut custom_properties: BTreeMap = Default::default(); + for (name, val) in table { + let val_str = val + .as_str() + .ok_or_else(|| format_err!("Field `{}` value must be a string", name))?; + custom_properties.insert(Symbol::from(name), val_str.to_owned()); + } Ok(PM::PackageInfo { name, version, authors, license, + custom_properties, }) } x => bail!( @@ -166,8 +181,8 @@ pub fn parse_dependencies(tval: TV) -> Result { TV::Table(table) => { let mut deps = BTreeMap::new(); for (dep_name, dep) in table.into_iter() { - let dep_name_ident = PM::PackageName::from(dep_name); - let dep = parse_dependency(dep)?; + let dep_name_ident = PM::PackageName::from(dep_name.clone()); + let dep = parse_dependency(&dep_name, dep)?; deps.insert(dep_name_ident, dep); } Ok(deps) @@ -291,21 +306,24 @@ fn parse_address_literal(address_str: &str) -> Result Result { +fn parse_dependency(dep_name: &str, tval: TV) -> Result { match tval { TV::Table(mut table) => { - warn_if_unknown_field_names( - &table, - &[ - "addr_subst", - "version", - "local", - "digest", - "git", - "rev", - "subdir", - ], - ); + let mut known_fields = vec![ + "addr_subst", + "version", + "local", + "digest", + "git", + "rev", + "subdir", + "address", + ]; + let custom_key_opt = &package_hooks::custom_dependency_key(); + if let Some(key) = custom_key_opt { + known_fields.push(key.as_ref()) + } + warn_if_unknown_field_names(&table, known_fields.as_slice()); let subst = table .remove("addr_subst") .map(parse_substitution) @@ -313,8 +331,17 @@ fn parse_dependency(tval: TV) -> Result { let version = table.remove("version").map(parse_version).transpose()?; let digest = table.remove("digest").map(parse_digest).transpose()?; let mut git_info = None; - match (table.remove("local"), table.remove("git")) { - (Some(local), None) => { + let mut node_info = None; + match ( + table.remove("local"), + table.remove("git"), + if let Some(key) = custom_key_opt { + table.remove(key) + } else { + None + }, + ) { + (Some(local), None, None) => { let local_str = local .as_str() .ok_or_else(|| format_err!("Local source path not a string"))?; @@ -325,10 +352,10 @@ fn parse_dependency(tval: TV) -> Result { digest, local: local_path, git_info, + node_info, }) } - (None, Some(git)) => { - // Look to see if a MOVE_HOME has been set. Otherwise default to $HOME + (None, Some(git), None) => { let move_home = MOVE_HOME.clone(); let rev_name = match table.remove("rev") { None => bail!("Git revision not supplied for dependency"), @@ -338,13 +365,12 @@ fn parse_dependency(tval: TV) -> Result { ), }; // Downloaded packages are of the form _ + let git_url = git + .as_str() + .ok_or_else(|| anyhow::anyhow!("Git URL not a string"))?; let local_path = PathBuf::from(move_home).join(format!( "{}_{}", - regex::Regex::new(r"/|:|\.|@").unwrap().replace_all( - git.as_str() - .ok_or_else(|| anyhow::anyhow!("Git URL not a string"))?, - "_" - ), + url_to_file_name(git_url), rev_name.replace('/', "__") )); let subdir = PathBuf::from(match table.remove("subdir") { @@ -355,10 +381,7 @@ fn parse_dependency(tval: TV) -> Result { .to_string(), }); git_info = Some(PM::GitInfo { - git_url: Symbol::from( - git.as_str() - .ok_or_else(|| format_err!("Git url not a string"))?, - ), + git_url: Symbol::from(git_url), git_rev: rev_name, subdir: subdir.clone(), download_to: local_path.clone(), @@ -370,13 +393,56 @@ fn parse_dependency(tval: TV) -> Result { digest, local: local_path.join(subdir), git_info, + node_info, }) } - (Some(_), Some(_)) => { - bail!("both 'local' and 'git' paths specified for dependency.") + (None, None, Some(custom_key)) => { + let package_name = Symbol::from(dep_name); + let address = match table.remove("address") { + None => bail!("Address not supplied for 'node' dependency"), + Some(r) => Symbol::from( + r.as_str() + .ok_or_else(|| format_err!("Node address not a string"))?, + ), + }; + // Downloaded packages are of the form _
_ + let node_url = custom_key + .as_str() + .ok_or_else(|| anyhow::anyhow!("Git URL not a string"))?; + let local_path = PathBuf::from(MOVE_HOME.clone()).join(format!( + "{}_{}_{}", + url_to_file_name(node_url), + address, + package_name + )); + node_info = Some(PM::CustomDepInfo { + node_url: Symbol::from(node_url), + package_address: address, + package_name, + download_to: local_path.clone(), + }); + Ok(PM::Dependency { + subst, + version, + digest, + local: local_path, + git_info, + node_info, + }) } - (None, None) => { - bail!("both 'local' and 'git' paths not specified for dependency.") + _ => { + let mut keys = vec!["local", "git"]; + if let Some(k) = custom_key_opt { + keys.push(k.as_str()) + } + let keys = keys + .into_iter() + .map(|s| format!("'{}'", s)) + .collect::>(); + bail!( + "must provide exactly one of {} for dependency.", + keys.join(" or ") + ) } } } @@ -384,6 +450,13 @@ fn parse_dependency(tval: TV) -> Result { } } +fn url_to_file_name(url: &str) -> String { + regex::Regex::new(r"/|:|\.|@") + .unwrap() + .replace_all(url, "_") + .to_string() +} + fn parse_substitution(tval: TV) -> Result { match tval { TV::Table(table) => { diff --git a/language/tools/move-package/src/source_package/parsed_manifest.rs b/language/tools/move-package/src/source_package/parsed_manifest.rs index f491fa1dc8..606fca7009 100644 --- a/language/tools/move-package/src/source_package/parsed_manifest.rs +++ b/language/tools/move-package/src/source_package/parsed_manifest.rs @@ -34,6 +34,7 @@ pub struct PackageInfo { pub version: Version, pub authors: Vec, pub license: Option, + pub custom_properties: BTreeMap, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -43,6 +44,7 @@ pub struct Dependency { pub version: Option, pub digest: Option, pub git_info: Option, + pub node_info: Option, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -58,6 +60,19 @@ pub struct GitInfo { pub download_to: PathBuf, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct CustomDepInfo { + /// The url of the node to download from + pub node_url: Symbol, + /// The address where the package is published. The representation depends + /// on the registered node resolver. + pub package_address: Symbol, + /// The address where the package is published. + pub package_name: Symbol, + /// Where the package is downloaded to. + pub download_to: PathBuf, +} + #[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct BuildInfo { pub language_version: Option, diff --git a/language/tools/move-package/tests/test_runner.rs b/language/tools/move-package/tests/test_runner.rs index 18ee00e373..3f72c5ec26 100644 --- a/language/tools/move-package/tests/test_runner.rs +++ b/language/tools/move-package/tests/test_runner.rs @@ -2,15 +2,22 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use anyhow::bail; use move_command_line_common::testing::{ add_update_baseline_fix, format_diff, read_env_update_baseline, EXP_EXT, }; use move_package::{ compilation::{build_plan::BuildPlan, model_builder::ModelBuilder}, + package_hooks, + package_hooks::PackageHooks, resolution::resolution_graph as RG, - source_package::{manifest_parser as MP, parsed_manifest::PackageDigest}, + source_package::{ + manifest_parser as MP, + parsed_manifest::{CustomDepInfo, PackageDigest}, + }, BuildConfig, ModelConfig, }; +use move_symbol_pool::Symbol; use std::{ ffi::OsStr, fs, @@ -22,6 +29,7 @@ const COMPILE_EXT: &str = "compile"; const MODEL_EXT: &str = "model"; pub fn run_test(path: &Path) -> datatest_stable::Result<()> { + package_hooks::register_package_hooks(Box::new(TestHooks())); let update_baseline = read_env_update_baseline(); if path .components() @@ -124,4 +132,31 @@ pub fn run_test(path: &Path) -> datatest_stable::Result<()> { Ok(()) } +/// Some dummy hooks for testing the hook mechanism +struct TestHooks(); + +impl PackageHooks for TestHooks { + fn custom_package_info_fields(&self) -> Vec { + vec!["test_hooks_field".to_owned()] + } + + fn custom_dependency_key(&self) -> Option { + Some("custom".to_owned()) + } + + fn resolve_custom_dependency( + &self, + dep_name: Symbol, + info: &CustomDepInfo, + ) -> anyhow::Result<()> { + bail!( + "TestHooks resolve dep {} = {} {} {}", + dep_name, + info.node_url, + info.package_name, + info.package_address + ) + } +} + datatest_stable::harness!(run_test, "tests/test_sources", r".*\.toml$"); diff --git a/language/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.exp b/language/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.exp index 0aa3f6aa02..65763af335 100644 --- a/language/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.exp +++ b/language/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -46,6 +47,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, diff --git a/language/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.exp b/language/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.exp index 539c3cdd96..6906f4935b 100644 --- a/language/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.exp +++ b/language/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -46,6 +47,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, diff --git a/language/tools/move-package/tests/test_sources/parsing/no_path_set_for_dependency/Move.exp b/language/tools/move-package/tests/test_sources/parsing/no_path_set_for_dependency/Move.exp index 53e2632f8f..8c3567f859 100644 --- a/language/tools/move-package/tests/test_sources/parsing/no_path_set_for_dependency/Move.exp +++ b/language/tools/move-package/tests/test_sources/parsing/no_path_set_for_dependency/Move.exp @@ -1 +1 @@ -Error parsing '[dependencies]' section of manifest: both 'local' and 'git' paths not specified for dependency. +Error parsing '[dependencies]' section of manifest: must provide exactly one of 'local' or 'git' or 'custom' for dependency. diff --git a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.exp b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.exp index 9187edcc25..88ecefeb75 100644 --- a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -46,6 +47,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, diff --git a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.exp b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.exp index 9d053f3d14..7cd6b1f870 100644 --- a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -52,6 +53,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { diff --git a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.exp b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.exp index 105824f328..694993bb91 100644 --- a/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -54,6 +55,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { diff --git a/language/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.exp b/language/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.exp index ab4d241291..c599d4e6d6 100644 --- a/language/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -48,6 +49,7 @@ ResolutionGraph { "6A88B7888D6049EB0121900E22B6FA2C0E702F042C8C8D4FD62AD5C990B9F9A8", ), git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -79,6 +81,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -109,6 +112,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -134,6 +138,7 @@ ResolutionGraph { "6A88B7888D6049EB0121900E22B6FA2C0E702F042C8C8D4FD62AD5C990B9F9A8", ), git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.exp b/language/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.exp index e55d032f09..cd5711fa69 100644 --- a/language/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -34,6 +35,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "B": Dependency { local: "./deps_only/B", @@ -47,6 +49,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -106,6 +109,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -123,6 +127,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -151,6 +156,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -168,6 +174,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -196,6 +203,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -226,6 +234,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -237,6 +246,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "B": Dependency { local: "./deps_only/B", @@ -250,6 +260,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.exp b/language/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.exp index ada69c02bf..f74f6a87ce 100644 --- a/language/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -40,6 +41,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "B": Dependency { local: "./deps_only/B", @@ -53,6 +55,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -112,6 +115,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -129,6 +133,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -157,6 +162,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -174,6 +180,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -202,6 +209,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -232,6 +240,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -249,6 +258,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "B": Dependency { local: "./deps_only/B", @@ -262,6 +272,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.exp b/language/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.exp index 9d098030d4..9e6a787ade 100644 --- a/language/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -40,6 +41,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "D": Dependency { local: "./deps_only/D", @@ -53,6 +55,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -94,6 +97,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -126,6 +130,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -158,6 +163,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -175,6 +181,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, "D": Dependency { local: "./deps_only/D", @@ -188,6 +195,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/one_dep/Move.exp b/language/tools/move-package/tests/test_sources/resolution/one_dep/Move.exp index 747f0ec048..0a225bf404 100644 --- a/language/tools/move-package/tests/test_sources/resolution/one_dep/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/one_dep/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -46,6 +47,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -77,6 +79,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -107,6 +110,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -130,6 +134,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.exp b/language/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.exp index a4ea059b17..f3b6a1384f 100644 --- a/language/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -40,6 +41,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -71,6 +73,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -103,6 +106,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: None, dev_address_assignments: None, @@ -120,6 +124,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.exp b/language/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.exp index f3c17bf94b..d073d1d5f3 100644 --- a/language/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -46,6 +47,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -77,6 +79,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -107,6 +110,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -130,6 +134,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.exp b/language/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.exp index 1fb3159e68..b0fd165cd8 100644 --- a/language/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -46,6 +47,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -77,6 +79,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -109,6 +112,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -132,6 +136,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.exp b/language/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.exp index d1270b23de..de214ddc88 100644 --- a/language/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.exp +++ b/language/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.exp @@ -23,6 +23,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -46,6 +47,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, @@ -77,6 +79,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -107,6 +110,7 @@ ResolutionGraph { ), authors: [], license: None, + custom_properties: {}, }, addresses: Some( { @@ -130,6 +134,7 @@ ResolutionGraph { version: None, digest: None, git_info: None, + node_info: None, }, }, dev_dependencies: {}, diff --git a/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.exp b/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.exp new file mode 100644 index 0000000000..9ff0f0e380 --- /dev/null +++ b/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.exp @@ -0,0 +1 @@ +Unable to resolve packages for package 'test': While resolving dependency 'Pkg' in package 'test': TestHooks resolve dep Pkg = localhost:8080 Pkg 0x1 diff --git a/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.toml b/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.toml new file mode 100644 index 0000000000..44b7370a10 --- /dev/null +++ b/language/tools/move-package/tests/test_sources/resolution/package_hooks/Move.toml @@ -0,0 +1,6 @@ +[package] +name = "test" +version = "0.0.0" + +[dependencies] +Pkg = { custom = "localhost:8080", address = "0x1", package = "framework" } From c8110e8ba6a8060660cc741d049cfdc5406dbb36 Mon Sep 17 00:00:00 2001 From: gmbows Date: Tue, 9 Aug 2022 11:54:16 -0500 Subject: [PATCH 050/169] [Build/WSL] Remove line-ending carriage returns in script files (#364) --- docker/move-cli/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/move-cli/Dockerfile b/docker/move-cli/Dockerfile index dcdb026b87..a3543ff5e6 100644 --- a/docker/move-cli/Dockerfile +++ b/docker/move-cli/Dockerfile @@ -20,6 +20,7 @@ ENV PATH "/opt/cargo/bin:/usr/lib/golang/bin:/opt/bin:${DOTNET_ROOT}:${DOTNET_RO RUN mkdir -p /github/home && \ mkdir -p /opt/cargo/ && \ mkdir -p /opt/git/ && \ + sed -i -e 's/\r$//' /move/scripts/*.sh && \ /move/scripts/dev_setup.sh -t -b -p -y -d -g -n && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* From 9bec0b1141d2e4141790fc1beb894b8bd09d0bd1 Mon Sep 17 00:00:00 2001 From: ruyisu Date: Tue, 9 Aug 2022 21:07:02 -0700 Subject: [PATCH 051/169] Fix typo of overla(p) (#367) Fix typo --- language/documentation/book/src/uses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/documentation/book/src/uses.md b/language/documentation/book/src/uses.md index 87d1914760..5e7edf8d9f 100644 --- a/language/documentation/book/src/uses.md +++ b/language/documentation/book/src/uses.md @@ -252,7 +252,7 @@ module example { Inside a given scope, all aliases introduced by `use` declarations must be unique. -For a module, this means aliases introduced by `use` cannot overla +For a module, this means aliases introduced by `use` cannot overlap ```move= address 0x42 { From 514cc0003a66f352f0259239ed688441e06da74c Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Wed, 10 Aug 2022 12:07:26 +0800 Subject: [PATCH 052/169] update introduction of move-book-zh (#366) --- .../move-book-zh/src/creating-coins.md | 6 ++- .../move-book-zh/src/introduction.md | 41 ++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/language/documentation/book/translations/move-book-zh/src/creating-coins.md b/language/documentation/book/translations/move-book-zh/src/creating-coins.md index 2fe52bad85..1f06df9a00 100644 --- a/language/documentation/book/translations/move-book-zh/src/creating-coins.md +++ b/language/documentation/book/translations/move-book-zh/src/creating-coins.md @@ -1,5 +1,7 @@ # Move Tutorial Please refer to the [Move Tutorial](https://github.com/move-language/move/tree/main/language/documentation/tutorial). -# 移动教程 -请参阅移动教程。 + +# Move 教程 + +请参阅 [Move 教程](https://github.com/move-language/move/tree/main/language/documentation/tutorial)。 diff --git a/language/documentation/book/translations/move-book-zh/src/introduction.md b/language/documentation/book/translations/move-book-zh/src/introduction.md index 21a46748f1..41da3ad656 100644 --- a/language/documentation/book/translations/move-book-zh/src/introduction.md +++ b/language/documentation/book/translations/move-book-zh/src/introduction.md @@ -3,10 +3,15 @@ Welcome to Move, a next generation language for secure, sandboxed, and formally verified programming. Its first use case is for the Diem blockchain, where Move provides the foundation for its implementation. Move allows developers to write programs that flexibly manage and transfer assets, while providing the security and protections against attacks on those assets. However, Move has been developed with use cases in mind outside a blockchain context as well. Move takes its cue from [Rust](https://www.rust-lang.org/) by using resource types with move (hence the name) semantics as an explicit representation of digital assets, such as currency. + # 介绍 -欢迎使用 Move,这是一种用于安全、沙盒和正式验证的编程的下一代语言。它的第一个用例是 Diem 区块链,Move 为其实施提供了基础。 Move 允许开发人员编写灵活管理和转移资产的程序,同时提供对这些资产的攻击的安全性和保护。然而,Move 的开发也考虑了区块链环境之外的用例。 -Move 通过使用具有 move(因此得名)语义的资源类型作为数字资产(例如货币)的显式表示,从 Rust 中汲取灵感。 +欢迎使用 Move,这是一种用于安全、沙盒和形式化验证的下一代编程语言。 +它的第一个用例是 Diem 区块链,Move 为其实现提供了基础。 +Move 允许开发人员编写灵活地管理和转移资产的程序,同时提供安全保护,防止那些对资产攻击的行为。 +不仅如此,Move 也可用于区块链之外的开发场景。 + +Move 的诞生从 [Rust](https://www.rust-lang.org/) 中的*所有权(ownership)*机制汲取了灵感,通过使用具有*移动(move)*语义的资源类型作为数字资产(例如货币)的显示表示,Move 也因此而得名。 ## Who is Move for? @@ -16,10 +21,13 @@ Given custom Move modules will not be supported at the [launch](https://diem.com The early Move Developer is one with some programming experience, who wants to begin understanding the core programming language and see examples of its usage. -## 为谁而动? -Move 被设计和创建为一种安全、经过验证且灵活的编程语言。 Move 的第一个用途是实现 Diem 区块链。也就是说,语言仍在不断发展。 Move 有可能成为其他区块链甚至非区块链用例的语言。 +## Move 是为谁而准备的? + +Move 被设计和创建为一种安全、经过验证且灵活的编程语言。 +Move 的第一个用途是实现 Diem 区块链。也就是说,语言仍在不断发展。 +Move 有可能成为其他区块链甚至非区块链用例的语言。 -鉴于在 Diem 支付网络 (DPN) 启动时将不支持自定义 Move 模块,我们的目标是早期的 Move 开发人员角色。 +鉴于在 Diem 支付网络 (DPN) 启动时将不支持自定义 Move 模块,我们的目标是早期的 Move 开发人员。 早期的 Move 开发人员是具有一定编程经验的人,他们希望开始了解核心编程语言并查看其使用示例。 @@ -28,22 +36,33 @@ Move 被设计和创建为一种安全、经过验证且灵活的编程语言。 Understanding that the capability to create custom modules on the Diem Payment Network will not be available at launch, the hobbyist Move Developer is interested in learning the intricacies of the language. She will understand the basic syntax, the standard libraries available, and write example code that can be executed using the Move CLI. The Move Developer may even want to dig into understanding how the Move Virtual Machine executes the code she writes. ### 爱好者 -了解在 Diem 支付网络上创建自定义模块的功能在发布时将不可用,爱好者 Move 开发人员有兴趣学习该语言的复杂性。她将了解基本语法、可用的标准库,并编写可以使用 Move CLI 执行的示例代码。 Move 开发人员甚至可能想深入了解 Move 虚拟机如何执行她编写的代码。 + +了解在 Diem 支付网络上创建自定义模块的功能在发布时将不可用,爱好 Move 的开发人员有兴趣学习该语言的复杂性。 +她将了解基本语法、可用的标准库,并编写可以使用 Move CLI 执行的示例代码。 +Move 开发人员甚至可能想深入了解 Move 虚拟机如何执行她编写的代码。 ### Core Contributor Beyond a hobbyist wanting to stay ahead of the curve for the core programming language is someone who may want to [contribute](https://diem.com/en-US/cla-sign/) directly to Move. Whether this includes submitting language improvements or even, in the future, adding core modules available on the Diem Payment Network, the core contributor will understand Move at a deep level. + ### 核心贡献者 -除了想要在核心编程语言方面保持领先的业余爱好者之外,还有可能想要直接为 Move 做出贡献的人。无论这包括提交语言改进,还是将来添加 Diem 支付网络上可用的核心模块,核心贡献者都将深入了解 Move。 + +除了想要在核心编程语言方面保持领先的业余爱好者之外,还有可能想要直接为 Move 做出贡献的人。 +无论这包括提交语言改进,还是将来添加 Diem 支付网络上可用的核心模块,核心贡献者都将深入了解 Move。 ### Who Move is currently not targeting Currently, Move is not targeting developers who wish to create custom modules and contracts for use on the Diem Payment Network. We are also not targeting novice developers who expect a completely polished developer experience even in testing the language. -### 目前未针对谁移动 -目前,Move 不针对希望创建自定义模块和合同以在 Diem 支付网络上使用的开发人员。我们也不针对新手开发者,他们希望即使在测试语言时也能获得完美的开发者体验。 + +### Move 目前不适用于哪些人 + +目前,Move 不针对希望创建自定义模块和合约以在 Diem 支付网络上使用的开发人员。 +我们也不针对那些期望在语言测试阶段就获得完美开发体验的新手开发者。 ## Where Do I Start? Begin with understanding [modules and scripts](./modules-and-scripts.md) and then work through the [Move Tutorial](./creating-coins.md). -## 我从哪说起呢? -从了解模块和脚本开始,然后完成移动教程。 + +## 我该从哪里开始呢? + +从了解[模块和脚本](./modules-and-scripts.md)开始,然后完成[Move 教程](./creating-coins.md)。 From b53bb030b556a4e6ac2728d50ec7baaddf0b9a56 Mon Sep 17 00:00:00 2001 From: jiangying Date: Thu, 11 Aug 2022 14:48:32 +0800 Subject: [PATCH 053/169] chore: fix typo (#370) --- language/move-core/types/src/language_storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/language/move-core/types/src/language_storage.rs b/language/move-core/types/src/language_storage.rs index c09f39bb27..b1a991b525 100644 --- a/language/move-core/types/src/language_storage.rs +++ b/language/move-core/types/src/language_storage.rs @@ -80,7 +80,7 @@ impl FromStr for StructTag { } } -/// Represents the intitial key into global storage where we first index by the address, and then +/// Represents the initial key into global storage where we first index by the address, and then /// the struct tag #[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)] pub struct ResourceKey { From f6490c1d13b5ba36c4d0c7b9724ac929b46cfac2 Mon Sep 17 00:00:00 2001 From: lerencao Date: Fri, 12 Aug 2022 04:13:17 +0800 Subject: [PATCH 054/169] [move-cli]: run test ignore compiler warnings (#371) --- language/tools/move-cli/src/base/test.rs | 16 ++++++++++++++-- language/tools/move-unit-test/src/lib.rs | 13 ++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/language/tools/move-cli/src/base/test.rs b/language/tools/move-cli/src/base/test.rs index e8bd2f8009..eb1f34914d 100644 --- a/language/tools/move-cli/src/base/test.rs +++ b/language/tools/move-cli/src/base/test.rs @@ -60,6 +60,11 @@ pub struct Test { /// Show the storage state at the end of execution of a failing test #[clap(name = "global_state_on_error", short = 'g', long = "state_on_error")] pub report_storage_on_error: bool, + + /// Ignore compiler's warning, and continue run tests + #[clap(name = "ignore_compile_warnings", long = "ignore_compile_warnings")] + pub ignore_compile_warnings: bool, + /// Use the stackless bytecode interpreter to run the tests and cross check its results with /// the execution result from Move VM. #[clap(long = "stackless")] @@ -93,6 +98,7 @@ impl Test { num_threads, report_statistics, report_storage_on_error, + ignore_compile_warnings, check_stackless_vm, verbose_mode, compute_coverage, @@ -108,7 +114,7 @@ impl Test { report_storage_on_error, check_stackless_vm, verbose: verbose_mode, - + ignore_compile_warnings, #[cfg(feature = "evm-backend")] evm, @@ -195,7 +201,13 @@ pub fn run_move_unit_tests( let (mut compiler, cfgir) = compiler.into_ast(); let compilation_env = compiler.compilation_env(); let built_test_plan = construct_test_plan(compilation_env, Some(root_package), &cfgir); - if let Err(diags) = compilation_env.check_diags_at_or_above_severity(Severity::Warning) { + if let Err(diags) = compilation_env.check_diags_at_or_above_severity( + if unit_test_config.ignore_compile_warnings { + Severity::NonblockingError + } else { + Severity::Warning + }, + ) { diagnostics::report_diagnostics(&files, diags); } diff --git a/language/tools/move-unit-test/src/lib.rs b/language/tools/move-unit-test/src/lib.rs index c3fb91736d..b98e984982 100644 --- a/language/tools/move-unit-test/src/lib.rs +++ b/language/tools/move-unit-test/src/lib.rs @@ -79,6 +79,10 @@ pub struct UnitTestingConfig { )] pub report_stacktrace_on_abort: bool, + /// Ignore compiler's warning, and continue run tests + #[clap(name = "ignore_compile_warnings", long = "ignore_compile_warnings")] + pub ignore_compile_warnings: bool, + /// Named address mapping #[clap( name = "NAMED_ADDRESSES", @@ -131,6 +135,7 @@ impl UnitTestingConfig { report_statistics: false, report_storage_on_error: false, report_stacktrace_on_abort: false, + ignore_compile_warnings: false, source_files: vec![], dep_files: vec![], check_stackless_vm: false, @@ -171,7 +176,13 @@ impl UnitTestingConfig { let compilation_env = compiler.compilation_env(); let test_plan = unit_test::plan_builder::construct_test_plan(compilation_env, None, &cfgir); - if let Err(diags) = compilation_env.check_diags_at_or_above_severity(Severity::Warning) { + if let Err(diags) = + compilation_env.check_diags_at_or_above_severity(if self.ignore_compile_warnings { + Severity::NonblockingError + } else { + Severity::Warning + }) + { diagnostics::report_diagnostics(&files, diags); } From 45a3e847c6920c3fafafcd6876a710551a403f33 Mon Sep 17 00:00:00 2001 From: vgao Date: Wed, 10 Aug 2022 15:52:57 -0700 Subject: [PATCH 055/169] [verifier] add option to limit nested loop depth --- Cargo.lock | 1 + .../src/unit_tests/code_unit_tests.rs | 12 +- .../src/unit_tests/control_flow_tests.rs | 58 ++++++- .../unit_tests/negative_stack_size_tests.rs | 8 +- .../src/code_unit_verifier.rs | 34 +++-- .../src/control_flow.rs | 43 +++++- language/move-bytecode-verifier/src/lib.rs | 5 +- .../move-bytecode-verifier/src/verifier.rs | 25 +++- language/move-core/types/src/vm_status.rs | 2 + language/move-vm/integration-tests/Cargo.toml | 1 + .../integration-tests/src/tests/mod.rs | 1 + .../src/tests/nested_loop_tests.rs | 141 ++++++++++++++++++ language/move-vm/runtime/src/loader.rs | 14 +- language/move-vm/runtime/src/move_vm.rs | 11 +- language/move-vm/runtime/src/runtime.rs | 5 +- 15 files changed, 317 insertions(+), 44 deletions(-) create mode 100644 language/move-vm/integration-tests/src/tests/nested_loop_tests.rs diff --git a/Cargo.lock b/Cargo.lock index d065f5baa7..7149107e15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3084,6 +3084,7 @@ version = "0.1.0" dependencies = [ "anyhow", "move-binary-format", + "move-bytecode-verifier", "move-compiler", "move-core-types", "move-stdlib", diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/code_unit_tests.rs b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/code_unit_tests.rs index e8091afb85..a18443b51c 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/code_unit_tests.rs +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/code_unit_tests.rs @@ -10,7 +10,7 @@ use move_core_types::vm_status::StatusCode; #[test] fn invalid_fallthrough_br_true() { let module = dummy_procedure_module(vec![Bytecode::LdFalse, Bytecode::BrTrue(1)]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -20,7 +20,7 @@ fn invalid_fallthrough_br_true() { #[test] fn invalid_fallthrough_br_false() { let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::BrFalse(1)]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -31,7 +31,7 @@ fn invalid_fallthrough_br_false() { #[test] fn invalid_fallthrough_non_branch() { let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::Pop]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -41,20 +41,20 @@ fn invalid_fallthrough_non_branch() { #[test] fn valid_fallthrough_branch() { let module = dummy_procedure_module(vec![Bytecode::Branch(0)]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert!(result.is_ok()); } #[test] fn valid_fallthrough_ret() { let module = dummy_procedure_module(vec![Bytecode::Ret]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert!(result.is_ok()); } #[test] fn valid_fallthrough_abort() { let module = dummy_procedure_module(vec![Bytecode::LdU64(7), Bytecode::Abort]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert!(result.is_ok()); } diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/control_flow_tests.rs b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/control_flow_tests.rs index ddf7796f3d..8a4317d953 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/control_flow_tests.rs +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/control_flow_tests.rs @@ -8,10 +8,10 @@ use move_binary_format::{ errors::PartialVMResult, file_format::{Bytecode, CompiledModule, FunctionDefinitionIndex, TableIndex}, }; -use move_bytecode_verifier::control_flow; +use move_bytecode_verifier::{control_flow, VerifierConfig}; use move_core_types::vm_status::StatusCode; -fn verify_module(module: &CompiledModule) -> PartialVMResult<()> { +fn verify_module(verifier_config: &VerifierConfig, module: &CompiledModule) -> PartialVMResult<()> { for (idx, function_definition) in module .function_defs() .iter() @@ -19,6 +19,7 @@ fn verify_module(module: &CompiledModule) -> PartialVMResult<()> { .filter(|(_, def)| !def.is_native()) { control_flow::verify( + verifier_config, Some(FunctionDefinitionIndex(idx as TableIndex)), function_definition .code @@ -36,7 +37,7 @@ fn verify_module(module: &CompiledModule) -> PartialVMResult<()> { #[test] fn invalid_fallthrough_br_true() { let module = dummy_procedure_module(vec![Bytecode::LdFalse, Bytecode::BrTrue(1)]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -46,7 +47,7 @@ fn invalid_fallthrough_br_true() { #[test] fn invalid_fallthrough_br_false() { let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::BrFalse(1)]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -57,7 +58,7 @@ fn invalid_fallthrough_br_false() { #[test] fn invalid_fallthrough_non_branch() { let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::Pop]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::INVALID_FALL_THROUGH @@ -67,20 +68,61 @@ fn invalid_fallthrough_non_branch() { #[test] fn valid_fallthrough_branch() { let module = dummy_procedure_module(vec![Bytecode::Branch(0)]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert!(result.is_ok()); } #[test] fn valid_fallthrough_ret() { let module = dummy_procedure_module(vec![Bytecode::Ret]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert!(result.is_ok()); } #[test] fn valid_fallthrough_abort() { let module = dummy_procedure_module(vec![Bytecode::LdU64(7), Bytecode::Abort]); - let result = verify_module(&module); + let result = verify_module(&Default::default(), &module); assert!(result.is_ok()); } + +#[test] +fn nested_loops_max_depth() { + let module = dummy_procedure_module(vec![ + Bytecode::LdFalse, + Bytecode::LdFalse, + Bytecode::BrFalse(1), + Bytecode::BrFalse(0), + Bytecode::Ret, + ]); + let result = verify_module( + &VerifierConfig { + max_loop_depth: Some(2), + }, + &module, + ); + assert!(result.is_ok()); +} + +#[test] +fn nested_loops_exceed_max_depth() { + let module = dummy_procedure_module(vec![ + Bytecode::LdFalse, + Bytecode::LdFalse, + Bytecode::LdFalse, + Bytecode::BrFalse(2), + Bytecode::BrFalse(1), + Bytecode::BrFalse(0), + Bytecode::Ret, + ]); + let result = verify_module( + &VerifierConfig { + max_loop_depth: Some(2), + }, + &module, + ); + assert_eq!( + result.unwrap_err().major_status(), + StatusCode::LOOP_MAX_DEPTH_REACHED + ); +} diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/negative_stack_size_tests.rs b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/negative_stack_size_tests.rs index ceacdcea50..c239747e3d 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/negative_stack_size_tests.rs +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/negative_stack_size_tests.rs @@ -10,7 +10,7 @@ use move_core_types::vm_status::StatusCode; #[test] fn one_pop_no_push() { let module = dummy_procedure_module(vec![Bytecode::Pop, Bytecode::Ret]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK @@ -21,7 +21,7 @@ fn one_pop_no_push() { fn one_pop_one_push() { // Height: 0 + (-1 + 1) = 0 would have passed original usage verifier let module = dummy_procedure_module(vec![Bytecode::ReadRef, Bytecode::Ret]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK @@ -32,7 +32,7 @@ fn one_pop_one_push() { fn two_pop_one_push() { // Height: 0 + 1 + (-2 + 1) = 0 would have passed original usage verifier let module = dummy_procedure_module(vec![Bytecode::LdU64(0), Bytecode::Add, Bytecode::Ret]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK @@ -42,7 +42,7 @@ fn two_pop_one_push() { #[test] fn two_pop_no_push() { let module = dummy_procedure_module(vec![Bytecode::WriteRef, Bytecode::Ret]); - let result = CodeUnitVerifier::verify_module(&module); + let result = CodeUnitVerifier::verify_module(&Default::default(), &module); assert_eq!( result.unwrap_err().major_status(), StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK diff --git a/language/move-bytecode-verifier/src/code_unit_verifier.rs b/language/move-bytecode-verifier/src/code_unit_verifier.rs index 13b96b20e5..79470e25c1 100644 --- a/language/move-bytecode-verifier/src/code_unit_verifier.rs +++ b/language/move-bytecode-verifier/src/code_unit_verifier.rs @@ -7,7 +7,7 @@ //! abstract_interpreter.rs. CodeUnitVerifier simply orchestrates calls into these two files. use crate::{ acquires_list_verifier::AcquiresVerifier, control_flow, locals_safety, reference_safety, - stack_usage_verifier::StackUsageVerifier, type_safety, + stack_usage_verifier::StackUsageVerifier, type_safety, verifier::VerifierConfig, }; use move_binary_format::{ access::ModuleAccess, @@ -28,26 +28,39 @@ pub struct CodeUnitVerifier<'a> { } impl<'a> CodeUnitVerifier<'a> { - pub fn verify_module(module: &'a CompiledModule) -> VMResult<()> { - Self::verify_module_impl(module).map_err(|e| e.finish(Location::Module(module.self_id()))) + pub fn verify_module( + verifier_config: &VerifierConfig, + module: &'a CompiledModule, + ) -> VMResult<()> { + Self::verify_module_impl(verifier_config, module) + .map_err(|e| e.finish(Location::Module(module.self_id()))) } - fn verify_module_impl(module: &'a CompiledModule) -> PartialVMResult<()> { + fn verify_module_impl( + verifier_config: &VerifierConfig, + module: &'a CompiledModule, + ) -> PartialVMResult<()> { for (idx, function_definition) in module.function_defs().iter().enumerate() { let index = FunctionDefinitionIndex(idx as TableIndex); - Self::verify_function(index, function_definition, module) + Self::verify_function(verifier_config, index, function_definition, module) .map_err(|err| err.at_index(IndexKind::FunctionDefinition, index.0))? } Ok(()) } - pub fn verify_script(module: &'a CompiledScript) -> VMResult<()> { - Self::verify_script_impl(module).map_err(|e| e.finish(Location::Script)) + pub fn verify_script( + verifier_config: &VerifierConfig, + module: &'a CompiledScript, + ) -> VMResult<()> { + Self::verify_script_impl(verifier_config, module).map_err(|e| e.finish(Location::Script)) } - fn verify_script_impl(script: &'a CompiledScript) -> PartialVMResult<()> { + fn verify_script_impl( + verifier_config: &VerifierConfig, + script: &'a CompiledScript, + ) -> PartialVMResult<()> { // create `FunctionView` and `BinaryIndexedView` - control_flow::verify(None, &script.code)?; + control_flow::verify(verifier_config, None, &script.code)?; let function_view = FunctionView::script(script); let resolver = BinaryIndexedView::Script(script); //verify @@ -60,6 +73,7 @@ impl<'a> CodeUnitVerifier<'a> { } fn verify_function( + verifier_config: &VerifierConfig, index: FunctionDefinitionIndex, function_definition: &'a FunctionDefinition, module: &'a CompiledModule, @@ -71,7 +85,7 @@ impl<'a> CodeUnitVerifier<'a> { }; // create `FunctionView` and `BinaryIndexedView` let function_handle = module.function_handle_at(function_definition.function); - control_flow::verify(Some(index), code)?; + control_flow::verify(verifier_config, Some(index), code)?; let function_view = FunctionView::function(module, index, code, function_handle); let resolver = BinaryIndexedView::Module(module); let mut name_def_map = HashMap::new(); diff --git a/language/move-bytecode-verifier/src/control_flow.rs b/language/move-bytecode-verifier/src/control_flow.rs index c2ed834801..784b88e6a4 100644 --- a/language/move-bytecode-verifier/src/control_flow.rs +++ b/language/move-bytecode-verifier/src/control_flow.rs @@ -7,6 +7,7 @@ //! - All forward jumps do not enter into the middle of a loop //! - All "breaks" (forward, loop-exiting jumps) go to the "end" of the loop //! - All "continues" (back jumps in a loop) are only to the current loop +use crate::verifier::VerifierConfig; use move_binary_format::{ errors::{PartialVMError, PartialVMResult}, file_format::{Bytecode, CodeOffset, CodeUnit, FunctionDefinitionIndex}, @@ -15,6 +16,7 @@ use move_core_types::vm_status::StatusCode; use std::{collections::HashSet, convert::TryInto}; pub fn verify( + verifier_config: &VerifierConfig, current_function_opt: Option, code: &CodeUnit, ) -> PartialVMResult<()> { @@ -36,7 +38,7 @@ pub fn verify( code: &code.code, }; let labels = instruction_labels(context); - check_jumps(context, labels) + check_jumps(verifier_config, context, labels) } #[derive(Clone, Copy)] @@ -95,13 +97,23 @@ fn instruction_labels(context: &ControlFlowVerifier) -> Vec