1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! The lex module provides a lexer for parsing commands.
//! It coudl be enabled with `"lex"` feature flag.
//!
//! ## Lex
//!
//! You can lex the command string with [`CommandLexer`].
//!
//! It produces following tokens:
//! - Basic raw string with pattern analysis
//! - Sequence of whitespace
//! - Quoted string
//! - Named raw string or quoted string
//!
//! See belo example for sure.
//! ```rust
//! # use kal::lex::{CommandLexer, CommandToken, RawStringPattern};
//! use CommandToken as Token;
//! use RawStringPattern as Pat;
//!
//! let mut lexer = CommandLexer::new(r#"hello world 1.0 3 "quote" named=value"#);
//! assert_eq!(lexer.next(), Some(Ok(Token::RawString("hello", Pat::Unrecognized))));
//! assert_eq!(lexer.next(), Some(Ok(Token::Whitespace(" "))));
//! assert_eq!(lexer.next(), Some(Ok(Token::RawString("world", Pat::Unrecognized))));
//! assert_eq!(lexer.next(), Some(Ok(Token::Whitespace(" "))));
//! assert_eq!(lexer.next(), Some(Ok(Token::RawString("1.0", Pat::Float))));
//! assert_eq!(lexer.next(), Some(Ok(Token::Whitespace(" "))));
//! assert_eq!(lexer.next(), Some(Ok(Token::RawString("3", Pat::Integer))));
//! assert_eq!(lexer.next(), Some(Ok(Token::Whitespace(" "))));
//! assert_eq!(lexer.next(), Some(Ok(Token::QuotedString("\"", "quote".to_string(), "\""))));
//! assert_eq!(lexer.next(), Some(Ok(Token::Whitespace(" "))));
//! assert_eq!(
//! lexer.next(),
//! Some(Ok(Token::Named(
//! "named",
//! Box::new(Token::RawString("value", Pat::Unrecognized)))
//! ))
//! );
//! assert_eq!(lexer.next(), None);
//! ```
//!
//! ## Transform
//!
//! Tokens contain too much information for command execution.
//! Thus, we will transform [`CommandToken`] to [`CommandFragment`](`crate::CommandFragment`).
//!
//! See xample below:
//!
//! ```rust
//! # use kal::lex::{CommandLexer, TokenTransformer, TransformHint};
//! # use kal::CommandFragment;
//! # use std::collections::HashMap;
//! let hint = TransformHint::Select(
//! HashMap::from_iter([("hello", TransformHint::Select(
//! HashMap::from_iter([("world", TransformHint::Execute(vec![]))])
//! ))])
//! );
//! let transformer = TokenTransformer::command_args(hint);
//! let lexer = CommandLexer::new("hello world");
//! let result: Result<Vec<_>, _> = transformer.transform(lexer).collect();
//! assert_eq!(
//! result,
//! Ok(vec![
//! CommandFragment::Select("hello".to_string()),
//! CommandFragment::Select("world".to_string()),
//! CommandFragment::Execute(vec![]),
//! ])
//! );
//! ```
//!
//! ### Label Strip
//!
//! Sometimes you need to strip the label for match command name correctly.
//! For example, you'll never need the leading `/` from `/hello` command.
//! You can easily strip leading/trailing string constants.
//! It is very useful when you're working with [`command_group!`](`crate::command_group!`).
//!
//! ```rust
//! # use kal::lex::{CommandLexer, TokenTransformer, TransformHint, remove_leading};
//! # use kal::CommandFragment;
//! # use std::collections::HashMap;
//! # let hint = TransformHint::Select(
//! # HashMap::from_iter([("hello", TransformHint::Select(
//! # HashMap::from_iter([("world", TransformHint::Execute(vec![]))])
//! # ))])
//! # );
//! let transformer = TokenTransformer::command_group(|s| remove_leading("/", s), hint);
//! let lexer = CommandLexer::new("/hello world");
//! let result: Result<Vec<_>, _> = transformer.transform(lexer).collect();
//! assert_eq!(
//! result,
//! Ok(vec![
//! CommandFragment::Select("hello".to_string()),
//! CommandFragment::Select("world".to_string()),
//! CommandFragment::Execute(vec![]),
//! ])
//! );
//! ```
//!
//! ### #[derive(TransformHintProvider)]
//!
//! As you can see above, the [`TokenTransformer`] needs [`TransformHint`] to work properly.
//! But writing hints hand-by-hand is a bit tedious job.
//! So, we provide a derive macro to generate it from an item.
//! Enable both `"lex"` and `"derive"` feature flags (later one is enabled by default),
//! and use `#[derive(TransformHintProvider)]` on your item.
//! It will take your `#[argument]` attributes for generating hints.
//!
//! ```rust
//! # use kal::Command;
//! # use kal::lex::{TransformHintProvider, TransformHint, TransformHintPart};
//! # use std::collections::HashMap;
//! #[derive(Command, TransformHintProvider)]
//! pub enum Hello {
//! World {
//! argument: String,
//! },
//! Sekai {
//! #[argument(take_rest)]
//! argument: String,
//! },
//! }
//!
//! assert_eq!(
//! Hello::hint(),
//! TransformHint::Select(HashMap::from_iter([
//! (
//! "world",
//! TransformHint::Execute(vec![TransformHintPart::String]),
//! ),
//! (
//! "sekai",
//! TransformHint::Execute(vec![TransformHintPart::StringGreedy]),
//! ),
//! ]))
//! );
//! ```
pub use TransformHintProvider;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;