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
use layered_nlp::{x, LLCursorAssignment, LLSelection, Resolver, TextTag};
use rust_decimal::Decimal;
#[derive(Clone, Debug)]
pub struct Amount(Decimal);
impl Amount {
pub fn get_decimal(&self) -> &Decimal {
&self.0
}
pub fn new<T: Into<Decimal>>(from: T) -> Self {
Self(from.into())
}
}
impl From<Decimal> for Amount {
fn from(dec: Decimal) -> Self {
Amount(dec)
}
}
pub struct AmountResolver {
delimiters: Vec<char>,
decimal: char,
}
impl AmountResolver {
pub fn new(delimiters: Vec<char>, decimal: char) -> Self {
Self {
delimiters,
decimal,
}
}
pub fn english() -> Self {
Self {
delimiters: vec![',', '\''],
decimal: '.',
}
}
pub fn french() -> Self {
Self {
delimiters: vec![' ', '.', '\''],
decimal: '.',
}
}
}
impl Resolver for AmountResolver {
type Attr = Amount;
fn go(&self, mut search_range_sel: LLSelection) -> Vec<LLCursorAssignment<Self::Attr>> {
let mut attrs = vec![];
while let Some((mut selection, (_, text))) =
search_range_sel.find_first_by(&x::all((x::attr_eq(&TextTag::NATN), x::token_text())))
{
let mut number_string = String::from(text);
let mut last_valid_selection = None;
loop {
if let Some((delimeter_sel, _)) =
selection.match_first_forwards(&x::token_has_any(self.delimiters.as_slice()))
{
last_valid_selection = Some(selection);
selection = delimeter_sel;
} else {
break;
}
if let Some((following_delimeter_sel, (_, text))) = selection
.match_first_forwards(&x::all((x::attr_eq(&TextTag::NATN), x::token_text())))
{
number_string.push_str(text);
last_valid_selection = None;
selection = following_delimeter_sel;
} else {
break;
}
}
if last_valid_selection.is_none() {
if let Some((with_decimal_sel, _)) =
selection.match_first_forwards(&x::token_has_any(&[self.decimal]))
{
last_valid_selection = Some(selection);
number_string.push('.');
selection = with_decimal_sel;
}
if let Some((following_decimal_sel, ((), text))) = selection
.match_first_forwards(&x::all((x::attr_eq(&TextTag::NATN), x::token_text())))
{
number_string.push_str(text);
last_valid_selection = None;
selection = following_decimal_sel;
}
}
attrs.push(
last_valid_selection
.unwrap_or_else(|| selection.clone())
.finish_with_attr(Amount(number_string.parse::<Decimal>().unwrap())),
);
if let [_, Some(right_sel)] = search_range_sel.split_with(&selection) {
search_range_sel = right_sel;
} else {
break;
}
}
attrs
}
}