Compare commits
8 Commits
3cc62129c7
...
88c4207aeb
Author | SHA1 | Date | |
---|---|---|---|
88c4207aeb | |||
18e4fef62f | |||
1f10bde1b4 | |||
3bbb64d065 | |||
478ccbb529 | |||
0a16edbc97 | |||
fad8d97212 | |||
e528c09623 |
175
Cargo.lock
generated
175
Cargo.lock
generated
@ -68,7 +68,7 @@ checksum = "9eac0a7f2d7cd7a93b938af401d3d8e8b7094217989a7c25c55a953023436e31"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"arrayvec 0.7.4",
|
"arrayvec",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"windows 0.48.0",
|
"windows 0.48.0",
|
||||||
@ -161,6 +161,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -233,12 +242,6 @@ version = "0.3.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arrayvec"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
@ -710,8 +713,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b"
|
checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"strum 0.24.1",
|
"strum",
|
||||||
"strum_macros 0.24.3",
|
"strum_macros",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -836,7 +839,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"serde",
|
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"signal-hook-mio",
|
"signal-hook-mio",
|
||||||
"winapi",
|
"winapi",
|
||||||
@ -928,6 +930,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
|||||||
name = "dust-lang"
|
name = "dust-lang"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"comfy-table",
|
"comfy-table",
|
||||||
@ -936,11 +939,10 @@ dependencies = [
|
|||||||
"egui_extras",
|
"egui_extras",
|
||||||
"git2",
|
"git2",
|
||||||
"json",
|
"json",
|
||||||
"nu-ansi-term",
|
|
||||||
"rand",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"reedline",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"rustyline",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
@ -1065,6 +1067,12 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "endian-type"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enumflags2"
|
name = "enumflags2"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
@ -1649,15 +1657,6 @@ version = "2.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.10.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
@ -1948,6 +1947,15 @@ dependencies = [
|
|||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nibble_vec"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.24.3"
|
version = "0.24.3"
|
||||||
@ -2010,15 +2018,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nu-ansi-term"
|
|
||||||
version = "0.49.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
@ -2365,6 +2364,16 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radix_trie"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
|
||||||
|
dependencies = [
|
||||||
|
"endian-type",
|
||||||
|
"nibble_vec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@ -2432,26 +2441,6 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "reedline"
|
|
||||||
version = "0.22.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2fde955d11817fdcb79d703932fb6b473192cb36b6a92ba21f7f4ac0513374e"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"crossterm",
|
|
||||||
"fd-lock",
|
|
||||||
"itertools",
|
|
||||||
"nu-ansi-term",
|
|
||||||
"serde",
|
|
||||||
"strip-ansi-escapes",
|
|
||||||
"strum 0.25.0",
|
|
||||||
"strum_macros 0.25.2",
|
|
||||||
"thiserror",
|
|
||||||
"unicode-segmentation",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.9.4"
|
version = "1.9.4"
|
||||||
@ -2557,6 +2546,41 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustyline"
|
||||||
|
version = "12.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "994eca4bca05c87e86e15d90fc7a91d1be64b4482b38cb2d27474568fe7c9db9"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.0",
|
||||||
|
"cfg-if",
|
||||||
|
"clipboard-win",
|
||||||
|
"fd-lock",
|
||||||
|
"home",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"nix 0.26.3",
|
||||||
|
"radix_trie",
|
||||||
|
"rustyline-derive",
|
||||||
|
"scopeguard",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"unicode-width",
|
||||||
|
"utf8parse",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustyline-derive"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a32af5427251d2e4be14fc151eabe18abb4a7aad5efee7044da9f096c906a43"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.29",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
@ -2830,15 +2854,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strip-ansi-escapes"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
|
|
||||||
dependencies = [
|
|
||||||
"vte",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -2851,12 +2866,6 @@ version = "0.24.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum"
|
|
||||||
version = "0.25.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
version = "0.24.3"
|
version = "0.24.3"
|
||||||
@ -2870,19 +2879,6 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum_macros"
|
|
||||||
version = "0.25.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn 2.0.29",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
@ -2971,7 +2967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67"
|
checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec 0.7.4",
|
"arrayvec",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"png",
|
"png",
|
||||||
@ -3228,27 +3224,6 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vte"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec 0.5.2",
|
|
||||||
"utf8parse",
|
|
||||||
"vte_generate_state_changes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vte_generate_state_changes"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -27,12 +27,12 @@ sysinfo = "0.29.6"
|
|||||||
toml = "0.7.6"
|
toml = "0.7.6"
|
||||||
toml_edit = "0.19.14"
|
toml_edit = "0.19.14"
|
||||||
comfy-table = "7.0.1"
|
comfy-table = "7.0.1"
|
||||||
reedline = "0.22.0"
|
|
||||||
clap = { version = "4.3.19", features = ["derive"] }
|
clap = { version = "4.3.19", features = ["derive"] }
|
||||||
nu-ansi-term = "0.49"
|
|
||||||
git2 = "0.17.2"
|
git2 = "0.17.2"
|
||||||
csv = "1.2.2"
|
csv = "1.2.2"
|
||||||
json = "0.12.4"
|
json = "0.12.4"
|
||||||
reqwest = { version = "0.11.18", features = ["blocking", "json"] }
|
reqwest = { version = "0.11.18", features = ["blocking", "json"] }
|
||||||
serde_json = "1.0.104"
|
serde_json = "1.0.104"
|
||||||
egui_extras = "0.22.0"
|
egui_extras = "0.22.0"
|
||||||
|
rustyline = { version = "12.0.0", features = ["with-file-history", "derive"] }
|
||||||
|
ansi_term = "0.12.1"
|
||||||
|
31
README.md
31
README.md
@ -32,9 +32,10 @@ read("examples/assets/faithful.csv")
|
|||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
|
- [Contributing](#contributing)
|
||||||
- [The Dust Programming Language](#the-dust-programming-language)
|
- [The Dust Programming Language](#the-dust-programming-language)
|
||||||
- [Variables and Data Types](#variables-and-data-types)
|
- [Variables and Data Types](#variables-and-data-types)
|
||||||
- [Commands](#commands)
|
- [Tools](#tools)
|
||||||
- [Lists](#lists)
|
- [Lists](#lists)
|
||||||
- [Maps](#maps)
|
- [Maps](#maps)
|
||||||
- [Tables](#tables)
|
- [Tables](#tables)
|
||||||
@ -56,6 +57,15 @@ read("examples/assets/faithful.csv")
|
|||||||
|
|
||||||
Dust is an experimental project under active development. At this stage, features come and go and the API is always changing. It should not be considered for serious use yet.
|
Dust is an experimental project under active development. At this stage, features come and go and the API is always changing. It should not be considered for serious use yet.
|
||||||
|
|
||||||
|
To get help with the shell you can use the "help" tool.
|
||||||
|
|
||||||
|
```dust
|
||||||
|
help() # Returns a table will all tool info.
|
||||||
|
help("random") # Returns a table with info on tools in the specified group.
|
||||||
|
# The above is simply a shorthand for this:
|
||||||
|
help() -> where(input, 'tool == "random"')
|
||||||
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
You must have the default rust toolchain installed and up-to-date. Install [rustup] if it is not already installed. Run `cargo install dust-lang` then run `dust` to start the interactive shell. Use `dust --help` to see the full command line options.
|
You must have the default rust toolchain installed and up-to-date. Install [rustup] if it is not already installed. Run `cargo install dust-lang` then run `dust` to start the interactive shell. Use `dust --help` to see the full command line options.
|
||||||
@ -98,9 +108,9 @@ map.key = "value";
|
|||||||
empty = ();
|
empty = ();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Commands
|
### Tools
|
||||||
|
|
||||||
**Commands** are dust's built-in tools. Some of them can reconfigure your whole system while others are do very little. They may accept different inputs, or none at all. commands in the `random` group can be run without input, but the `random_integer` command can optionally take two numbers as in inclusive range.
|
**Tools** are dust's built-in functions. Some of them can reconfigure your whole system while others do very little. They may accept different inputs, or none at all. For example, commands in the `random` group can be run without input, but the `random_integer` command can optionally take two numbers as in inclusive range.
|
||||||
|
|
||||||
```dust
|
```dust
|
||||||
die_roll = random_integer(1, 6);
|
die_roll = random_integer(1, 6);
|
||||||
@ -108,21 +118,24 @@ d20_roll = random_integer(1, 20);
|
|||||||
coin_flip = random_boolean();
|
coin_flip = random_boolean();
|
||||||
```
|
```
|
||||||
|
|
||||||
Other commands can be found by pressing TAB in the interactive shell.
|
|
||||||
|
|
||||||
```dust
|
```dust
|
||||||
message = "I hate dust.";
|
message = "I hate dust.";
|
||||||
replace(message, "hate", "love");
|
replace(message, "hate", "love")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lists
|
### Lists
|
||||||
|
|
||||||
Lists are sequential collections. They can be built by grouping values with parentheses and separating them with commas. Values can be indexed by their position to access their contents. Lists are used to represent rows in tables and most commands take a list as an argument.
|
Lists are sequential collections. They can be built by grouping values with parentheses and separating them with commas. Values can be indexed by their position to access their contents. Lists are used to represent rows in tables and most commands take a list as an argument. Their contents can be indexed using dot notation with an integer.
|
||||||
|
|
||||||
```dust
|
```dust
|
||||||
list = (true, 42, "Ok");
|
list = (true, 41, "Ok");
|
||||||
|
|
||||||
assert_equal(list.0, true);
|
assert_equal(list.0, true);
|
||||||
|
|
||||||
|
list.1 = list.1 + 1;
|
||||||
|
|
||||||
|
assert_equal(list.1, 42);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Maps
|
### Maps
|
||||||
@ -157,7 +170,7 @@ Querying a table is similar to SQL.
|
|||||||
```dust
|
```dust
|
||||||
names = select(animals, "name");
|
names = select(animals, "name");
|
||||||
youngins = where(animals, 'age < 5');
|
youngins = where(animals, 'age < 5');
|
||||||
old_species = select_where(animals, "species", 'age > 5')
|
old_species = select_where(animals, "species", 'age > 5');
|
||||||
```
|
```
|
||||||
|
|
||||||
The commands `create_table` and `insert` make sure that all of the memory used to hold the rows is allocated at once, so it is good practice to group your rows together instead of using a call for each row.
|
The commands `create_table` and `insert` make sure that all of the memory used to hold the rows is allocated at once, so it is good practice to group your rows together instead of using a call for each row.
|
||||||
|
307
src/bin/dust.rs
307
src/bin/dust.rs
@ -1,18 +1,17 @@
|
|||||||
//! Command line interface for the whale programming language.
|
//! Command line interface for the whale programming language.
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use nu_ansi_term::{Color, Style};
|
use rustyline::{
|
||||||
use reedline::{
|
completion::FilenameCompleter,
|
||||||
default_emacs_keybindings, ColumnarMenu, Completer, DefaultHinter, DefaultPrompt,
|
error::ReadlineError,
|
||||||
DefaultPromptSegment, EditCommand, Emacs, FileBackedHistory, KeyCode, KeyModifiers, Reedline,
|
highlight::Highlighter,
|
||||||
ReedlineEvent, ReedlineMenu, Signal, Span, Suggestion,
|
hint::{Hint, Hinter, HistoryHinter},
|
||||||
|
history::DefaultHistory,
|
||||||
|
Completer, Context, Editor, Helper, Validator,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{borrow::Cow, fs::read_to_string};
|
||||||
fs::{self, read_to_string},
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
|
|
||||||
use dust_lib::{eval, eval_with_context, Tool, ToolInfo, Value, VariableMap, TOOL_LIST};
|
use dust_lib::{eval, eval_with_context, Value, VariableMap, TOOL_LIST};
|
||||||
|
|
||||||
/// Command-line arguments to be parsed.
|
/// Command-line arguments to be parsed.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -49,205 +48,121 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Helper, Completer, Validator)]
|
||||||
|
struct DustReadline {
|
||||||
|
#[rustyline(Completer)]
|
||||||
|
completer: FilenameCompleter,
|
||||||
|
|
||||||
|
tool_hints: Vec<ToolHint>,
|
||||||
|
|
||||||
|
#[rustyline(Hinter)]
|
||||||
|
_hinter: HistoryHinter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DustReadline {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
completer: FilenameCompleter::new(),
|
||||||
|
_hinter: HistoryHinter {},
|
||||||
|
tool_hints: TOOL_LIST
|
||||||
|
.iter()
|
||||||
|
.map(|tool| ToolHint {
|
||||||
|
display: tool.info().identifier.to_string(),
|
||||||
|
complete_to: tool.info().identifier.len(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ToolHint {
|
||||||
|
display: String,
|
||||||
|
complete_to: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hint for ToolHint {
|
||||||
|
fn display(&self) -> &str {
|
||||||
|
&self.display
|
||||||
|
}
|
||||||
|
|
||||||
|
fn completion(&self) -> Option<&str> {
|
||||||
|
if self.complete_to > 0 {
|
||||||
|
Some(&self.display[..self.complete_to])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToolHint {
|
||||||
|
fn suffix(&self, strip_chars: usize) -> ToolHint {
|
||||||
|
ToolHint {
|
||||||
|
display: self.display[strip_chars..].to_string(),
|
||||||
|
complete_to: self.complete_to.saturating_sub(strip_chars),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hinter for DustReadline {
|
||||||
|
type Hint = ToolHint;
|
||||||
|
|
||||||
|
fn hint(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Option<Self::Hint> {
|
||||||
|
if line.is_empty() || pos < line.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tool_hints.iter().find_map(|tool_hint| {
|
||||||
|
if tool_hint.display.starts_with(line) {
|
||||||
|
Some(tool_hint.suffix(pos))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Highlighter for DustReadline {
|
||||||
|
fn highlight_hint<'h>(&self, hint: &'h str) -> std::borrow::Cow<'h, str> {
|
||||||
|
let highlighted = ansi_term::Colour::Red.paint(hint).to_string();
|
||||||
|
|
||||||
|
Cow::Owned(highlighted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_cli_shell() {
|
fn run_cli_shell() {
|
||||||
let mut context = VariableMap::new();
|
let mut context = VariableMap::new();
|
||||||
let mut line_editor = setup_reedline();
|
let mut rl: Editor<DustReadline, DefaultHistory> = Editor::new().unwrap();
|
||||||
let prompt = DefaultPrompt {
|
|
||||||
left_prompt: DefaultPromptSegment::WorkingDirectory,
|
rl.set_helper(Some(DustReadline::new()));
|
||||||
right_prompt: DefaultPromptSegment::CurrentDateTime,
|
|
||||||
};
|
if rl.load_history("target/history.txt").is_err() {
|
||||||
|
println!("No previous history.");
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let sig = line_editor.read_line(&prompt);
|
let readline = rl.readline("* ");
|
||||||
|
match readline {
|
||||||
|
Ok(line) => {
|
||||||
|
let line = line.as_str();
|
||||||
|
|
||||||
match sig {
|
rl.add_history_entry(line).unwrap();
|
||||||
Ok(Signal::Success(buffer)) => {
|
|
||||||
let eval_result = eval_with_context(&buffer, &mut context);
|
let eval_result = eval_with_context(line, &mut context);
|
||||||
|
|
||||||
match eval_result {
|
match eval_result {
|
||||||
Ok(value) => println!("{value}"),
|
Ok(value) => println!("{value}"),
|
||||||
Err(error) => eprintln!("{error}"),
|
Err(error) => eprintln!("{error}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => {
|
Err(ReadlineError::Interrupted) => {
|
||||||
println!("\nExit");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
signal => {
|
Err(ReadlineError::Eof) => {
|
||||||
println!("Unhandled signal: {:?}", signal);
|
break;
|
||||||
}
|
}
|
||||||
|
Err(error) => eprintln!("{error}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
rl.save_history("target/history.txt").unwrap();
|
||||||
struct WhaleCompeleter {
|
|
||||||
macro_list: Vec<Suggestion>,
|
|
||||||
files: Vec<Suggestion>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WhaleCompeleter {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
WhaleCompeleter {
|
|
||||||
macro_list: Vec::new(),
|
|
||||||
files: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_command_list(&mut self, macro_list: Vec<&'static dyn Tool>) -> &mut Self {
|
|
||||||
self.macro_list = macro_list
|
|
||||||
.iter()
|
|
||||||
.map(|r#macro| {
|
|
||||||
let ToolInfo {
|
|
||||||
identifier,
|
|
||||||
description,
|
|
||||||
group,
|
|
||||||
inputs,
|
|
||||||
} = r#macro.info();
|
|
||||||
|
|
||||||
let description = format!("{description} | {group}");
|
|
||||||
let inputs = inputs
|
|
||||||
.iter()
|
|
||||||
.map(|value_type| value_type.to_string())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Suggestion {
|
|
||||||
value: identifier.to_string() + "()",
|
|
||||||
description: Some(description),
|
|
||||||
extra: Some(inputs),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
self.macro_list
|
|
||||||
.sort_by_key(|suggestion| suggestion.extra.clone());
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_suggestions(&mut self, start: usize, end: usize) -> Vec<Suggestion> {
|
|
||||||
let macro_suggestions = self
|
|
||||||
.macro_list
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.map(|suggestion| Suggestion {
|
|
||||||
span: Span { start, end },
|
|
||||||
..suggestion
|
|
||||||
});
|
|
||||||
let file_suggestions = self.files.iter().cloned().map(|suggestion| Suggestion {
|
|
||||||
span: Span { start, end },
|
|
||||||
..suggestion
|
|
||||||
});
|
|
||||||
|
|
||||||
file_suggestions.chain(macro_suggestions).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_files(&mut self, mut path: &str) {
|
|
||||||
if path.starts_with('\"') {
|
|
||||||
path = &path[1..];
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = PathBuf::from(path);
|
|
||||||
|
|
||||||
if !path.is_dir() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.files = fs::read_dir(path)
|
|
||||||
.unwrap()
|
|
||||||
.map(|entry| {
|
|
||||||
let path = entry.unwrap().path();
|
|
||||||
let path = path.to_string_lossy();
|
|
||||||
|
|
||||||
Suggestion {
|
|
||||||
value: format!("\"{path}\""),
|
|
||||||
description: None,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Completer for WhaleCompeleter {
|
|
||||||
fn complete(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
|
|
||||||
let split = line.split(' ');
|
|
||||||
let current_word = split.last().unwrap_or("");
|
|
||||||
let start = pos.saturating_sub(current_word.len());
|
|
||||||
let end = line.len();
|
|
||||||
|
|
||||||
self.update_files(current_word);
|
|
||||||
self.get_suggestions(start, end)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_reedline() -> Reedline {
|
|
||||||
let mut completer = Box::new(WhaleCompeleter::new());
|
|
||||||
|
|
||||||
completer.set_command_list(TOOL_LIST.to_vec());
|
|
||||||
|
|
||||||
let completion_menu = Box::new(
|
|
||||||
ColumnarMenu::default()
|
|
||||||
.with_name("completion_menu")
|
|
||||||
.with_columns(1)
|
|
||||||
.with_text_style(Style {
|
|
||||||
foreground: Some(Color::White),
|
|
||||||
is_dimmed: false,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_description_text_style(Style {
|
|
||||||
is_dimmed: true,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_selected_text_style(Style {
|
|
||||||
is_bold: true,
|
|
||||||
background: Some(Color::Black),
|
|
||||||
foreground: Some(Color::White),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut keybindings = default_emacs_keybindings();
|
|
||||||
keybindings.add_binding(
|
|
||||||
KeyModifiers::NONE,
|
|
||||||
KeyCode::Tab,
|
|
||||||
ReedlineEvent::UntilFound(vec![
|
|
||||||
ReedlineEvent::Menu("completion_menu".to_string()),
|
|
||||||
ReedlineEvent::MenuNext,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
keybindings.add_binding(
|
|
||||||
KeyModifiers::SHIFT,
|
|
||||||
KeyCode::Tab,
|
|
||||||
ReedlineEvent::UntilFound(vec![
|
|
||||||
ReedlineEvent::Menu("completion_menu".to_string()),
|
|
||||||
ReedlineEvent::MenuPrevious,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
keybindings.add_binding(
|
|
||||||
KeyModifiers::ALT,
|
|
||||||
KeyCode::Enter,
|
|
||||||
ReedlineEvent::Edit(vec![EditCommand::InsertNewline]),
|
|
||||||
);
|
|
||||||
|
|
||||||
let edit_mode = Box::new(Emacs::new(keybindings));
|
|
||||||
let history = Box::new(
|
|
||||||
FileBackedHistory::with_file(100, "target/history.txt".into())
|
|
||||||
.expect("Error configuring shell history file."),
|
|
||||||
);
|
|
||||||
let mut hinter = DefaultHinter::default();
|
|
||||||
|
|
||||||
hinter = hinter.with_style(Style {
|
|
||||||
foreground: Some(Color::Yellow),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
Reedline::create()
|
|
||||||
.with_completer(completer)
|
|
||||||
.with_menu(ReedlineMenu::EngineCompleter(completion_menu))
|
|
||||||
.with_edit_mode(edit_mode)
|
|
||||||
.with_history(history)
|
|
||||||
.with_hinter(Box::new(hinter))
|
|
||||||
.with_partial_completions(true)
|
|
||||||
.with_quick_completions(true)
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,58 @@ use std::{thread::sleep, time::Duration};
|
|||||||
|
|
||||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::{Result, Tool, ToolInfo, Value, ValueType};
|
use crate::{Result, Table, Tool, ToolInfo, Value, ValueType, TOOL_LIST};
|
||||||
|
|
||||||
|
pub struct Help;
|
||||||
|
|
||||||
|
impl Tool for Help {
|
||||||
|
fn info(&self) -> ToolInfo<'static> {
|
||||||
|
ToolInfo {
|
||||||
|
identifier: "help",
|
||||||
|
description: "Get help using dust.",
|
||||||
|
group: "general",
|
||||||
|
inputs: vec![ValueType::Empty, ValueType::String],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, argument: &Value) -> Result<Value> {
|
||||||
|
self.check_type(argument)?;
|
||||||
|
|
||||||
|
let mut table = Table::new(vec![
|
||||||
|
"tool".to_string(),
|
||||||
|
"description".to_string(),
|
||||||
|
"group".to_string(),
|
||||||
|
"inputs".to_string(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for tool in TOOL_LIST {
|
||||||
|
let tool_group = tool.info().group.to_string();
|
||||||
|
|
||||||
|
if let Ok(group) = argument.as_string() {
|
||||||
|
if &tool_group != group {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let row = vec![
|
||||||
|
Value::String(tool.info().identifier.to_string()),
|
||||||
|
Value::String(tool.info().description.to_string()),
|
||||||
|
Value::String(tool_group),
|
||||||
|
Value::List(
|
||||||
|
tool.info()
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.map(|value_type| Value::String(value_type.to_string()))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
table.insert(row)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Table(table))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Output;
|
pub struct Output;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ pub mod time;
|
|||||||
/// Master list of all tools.
|
/// Master list of all tools.
|
||||||
///
|
///
|
||||||
/// This list is used to match identifiers with tools and to provide info to the shell.
|
/// This list is used to match identifiers with tools and to provide info to the shell.
|
||||||
pub const TOOL_LIST: [&'static dyn Tool; 51] = [
|
pub const TOOL_LIST: [&'static dyn Tool; 52] = [
|
||||||
&collections::Count,
|
&collections::Count,
|
||||||
&collections::CreateTable,
|
&collections::CreateTable,
|
||||||
&collections::Insert,
|
&collections::Insert,
|
||||||
@ -82,6 +82,7 @@ pub const TOOL_LIST: [&'static dyn Tool; 51] = [
|
|||||||
&filesystem::Trash,
|
&filesystem::Trash,
|
||||||
&filesystem::Watch,
|
&filesystem::Watch,
|
||||||
&filesystem::Write,
|
&filesystem::Write,
|
||||||
|
&general::Help,
|
||||||
&general::Run,
|
&general::Run,
|
||||||
&general::Output,
|
&general::Output,
|
||||||
&general::Repeat,
|
&general::Repeat,
|
||||||
|
@ -162,7 +162,21 @@ impl Display for Table {
|
|||||||
for row in &self.rows {
|
for row in &self.rows {
|
||||||
let row = row.iter().map(|value| {
|
let row = row.iter().map(|value| {
|
||||||
let text = match value {
|
let text = match value {
|
||||||
Value::List(list) => format!("{list:?}"),
|
Value::List(list) => {
|
||||||
|
let mut string = "(".to_string();
|
||||||
|
|
||||||
|
for (index, value) in list.into_iter().enumerate() {
|
||||||
|
if index > 0 {
|
||||||
|
string.push_str(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
string.push_str(&value.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
string.push_str(")");
|
||||||
|
|
||||||
|
string
|
||||||
|
}
|
||||||
Value::Map(map) => format!("Map ({} items)", map.len()),
|
Value::Map(map) => format!("Map ({} items)", map.len()),
|
||||||
Value::Table(table) => format!("Table ({} items)", table.len()),
|
Value::Table(table) => format!("Table ({} items)", table.len()),
|
||||||
Value::Function(_) => "Function".to_string(),
|
Value::Function(_) => "Function".to_string(),
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
//! Representation of a moment in time.
|
//! Representation of a moment in time.
|
||||||
//!
|
//!
|
||||||
//! Whale represent time values correctly. To do this, there must be a clear separation between
|
//! Dust tries to represent time values correctly. To do this, there must be a clear separation
|
||||||
//! monotonic timestamps, naive times that do not know their locale and those that have a timezone.
|
//! between monotonic timestamps, naive times that do not know their locale and those that have a ..
|
||||||
|
//! timezone.
|
||||||
//!
|
//!
|
||||||
//! Only monotonic time instances are guaranteed not to repeat, although and Instance can be used to
|
//! Only monotonic time instances are guaranteed not to repeat, although an Instant can be used to
|
||||||
//! create and of these variants. Users generally want the timezone included, so the `as_local` is
|
//! create and of these variants. Users generally want the timezone included, so the `as_local` is
|
||||||
//! included, which will use no timezone offset if one is not available.
|
//! included, which will use no timezone offset if one is not available.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
time::{Instant, SystemTime},
|
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, FixedOffset, Local as LocalTime, NaiveDateTime};
|
use chrono::{DateTime, FixedOffset, Local as LocalTime, NaiveDateTime};
|
||||||
@ -54,7 +55,7 @@ impl Time {
|
|||||||
Time::Utc(utc) => DateTime::from_utc(utc, FixedOffset::west_opt(0).unwrap()),
|
Time::Utc(utc) => DateTime::from_utc(utc, FixedOffset::west_opt(0).unwrap()),
|
||||||
Time::Local(local) => local,
|
Time::Local(local) => local,
|
||||||
Time::Monotonic(instant) => DateTime::from_utc(
|
Time::Monotonic(instant) => DateTime::from_utc(
|
||||||
NaiveDateTime::from_timestamp_micros(instant.elapsed().as_micros() as i64).unwrap(),
|
NaiveDateTime::from_timestamp_millis(instant.elapsed().as_millis() as i64).unwrap(),
|
||||||
FixedOffset::west_opt(0).unwrap(),
|
FixedOffset::west_opt(0).unwrap(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@ -65,7 +66,11 @@ impl Time {
|
|||||||
|
|
||||||
impl Display for Time {
|
impl Display for Time {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.as_local())
|
match self {
|
||||||
|
Time::Utc(inner) => write!(f, "{}", inner),
|
||||||
|
Time::Local(inner) => write!(f, "{}", inner),
|
||||||
|
Time::Monotonic(inner) => write!(f, "{:?}", inner),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
|
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
/// The type of a `Value`.
|
/// The type of a `Value`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub enum ValueType {
|
pub enum ValueType {
|
||||||
Any,
|
Any,
|
||||||
String,
|
String,
|
||||||
@ -38,11 +38,9 @@ impl PartialEq for ValueType {
|
|||||||
(ValueType::ListOf(_), ValueType::List) => true,
|
(ValueType::ListOf(_), ValueType::List) => true,
|
||||||
(ValueType::List, ValueType::ListOf(_)) => true,
|
(ValueType::List, ValueType::ListOf(_)) => true,
|
||||||
(ValueType::ListOf(value_type), ValueType::ListExact(exact_list))
|
(ValueType::ListOf(value_type), ValueType::ListExact(exact_list))
|
||||||
| (ValueType::ListExact(exact_list), ValueType::ListOf(value_type)) => {
|
| (ValueType::ListExact(exact_list), ValueType::ListOf(value_type)) => exact_list
|
||||||
exact_list
|
|
||||||
.iter()
|
.iter()
|
||||||
.all(|exact_type| exact_type == value_type.as_ref())
|
.all(|exact_type| exact_type == value_type.as_ref()),
|
||||||
}
|
|
||||||
(ValueType::List, ValueType::List) => true,
|
(ValueType::List, ValueType::List) => true,
|
||||||
(ValueType::Empty, ValueType::Empty) => true,
|
(ValueType::Empty, ValueType::Empty) => true,
|
||||||
(ValueType::Map, ValueType::Map) => true,
|
(ValueType::Map, ValueType::Map) => true,
|
||||||
@ -55,7 +53,7 @@ impl PartialEq for ValueType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ValueType {
|
impl Display for ValueType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match &self {
|
match &self {
|
||||||
ValueType::Any => write!(f, "any"),
|
ValueType::Any => write!(f, "any"),
|
||||||
ValueType::String => write!(f, "string"),
|
ValueType::String => write!(f, "string"),
|
||||||
@ -64,15 +62,19 @@ impl Display for ValueType {
|
|||||||
ValueType::Boolean => write!(f, "boolean"),
|
ValueType::Boolean => write!(f, "boolean"),
|
||||||
ValueType::List => write!(f, "list"),
|
ValueType::List => write!(f, "list"),
|
||||||
ValueType::ListOf(value_type) => {
|
ValueType::ListOf(value_type) => {
|
||||||
write!(f, "list of {value_type}")
|
write!(f, "({value_type}s)")
|
||||||
}
|
}
|
||||||
ValueType::ListExact(list) => {
|
ValueType::ListExact(list) => {
|
||||||
let items = list
|
write!(f, "(")?;
|
||||||
.iter()
|
for (index, item) in list.into_iter().enumerate() {
|
||||||
.map(|value_type| value_type.to_string() + " ")
|
if index > 0 {
|
||||||
.collect::<String>();
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
write!(f, "list of {items}")
|
write!(f, "{item}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
ValueType::Empty => write!(f, "empty"),
|
ValueType::Empty => write!(f, "empty"),
|
||||||
ValueType::Map => write!(f, "map"),
|
ValueType::Map => write!(f, "map"),
|
||||||
@ -83,6 +85,12 @@ impl Display for ValueType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for ValueType {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{self}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Value> for ValueType {
|
impl From<&Value> for ValueType {
|
||||||
fn from(value: &Value) -> Self {
|
fn from(value: &Value) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
@ -111,7 +111,7 @@ impl VariableMap {
|
|||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut missing_elements = index - list.len() + 1;
|
let mut missing_elements = index.saturating_sub(list.len()) + 1;
|
||||||
|
|
||||||
while missing_elements > 0 {
|
while missing_elements > 0 {
|
||||||
list.push(value.clone());
|
list.push(value.clone());
|
||||||
|
Loading…
Reference in New Issue
Block a user