Skip to content

Commit 80ca240

Browse files
committed
refactor(path): Switch from recursive to iterative structures
1 parent c397a10 commit 80ca240

File tree

2 files changed

+127
-146
lines changed

2 files changed

+127
-146
lines changed

src/path/mod.rs

Lines changed: 77 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ use crate::value::{Value, ValueKind};
77
mod parser;
88

99
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
10-
pub(crate) enum Expression {
11-
Identifier(String),
12-
Child(Box<Self>, String),
13-
Subscript(Box<Self>, isize),
10+
pub(crate) struct Expression {
11+
root: String,
12+
postfix: Vec<Postfix>,
1413
}
1514

1615
impl Expression {
1716
pub(crate) fn root(root: String) -> Self {
18-
Expression::Identifier(root)
17+
Self {
18+
root,
19+
postfix: Vec::new(),
20+
}
1921
}
2022
}
2123

@@ -29,6 +31,12 @@ impl FromStr for Expression {
2931
}
3032
}
3133

34+
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
35+
enum Postfix {
36+
Key(String),
37+
Index(isize),
38+
}
39+
3240
#[derive(Debug)]
3341
struct ParseError(String);
3442

@@ -59,105 +67,83 @@ fn abs_index(index: isize, len: usize) -> Result<usize, usize> {
5967

6068
impl Expression {
6169
pub(crate) fn get(self, root: &Value) -> Option<&Value> {
62-
match self {
63-
Self::Identifier(key) => {
64-
match root.kind {
65-
// `x` access on a table is equivalent to: map[x]
66-
ValueKind::Table(ref map) => map.get(&key),
67-
68-
// all other variants return None
69-
_ => None,
70+
let ValueKind::Table(map) = &root.kind else {
71+
return None;
72+
};
73+
let mut child = map.get(&self.root)?;
74+
for postfix in &self.postfix {
75+
match postfix {
76+
Postfix::Key(key) => {
77+
let ValueKind::Table(map) = &child.kind else {
78+
return None;
79+
};
80+
child = map.get(key)?;
7081
}
71-
}
72-
73-
Self::Child(expr, key) => {
74-
match expr.get(root) {
75-
Some(child) => {
76-
match child.kind {
77-
// Access on a table is identical to Identifier, it just forwards
78-
ValueKind::Table(ref map) => map.get(&key),
79-
80-
// all other variants return None
81-
_ => None,
82-
}
83-
}
84-
85-
_ => None,
82+
Postfix::Index(rel_index) => {
83+
let ValueKind::Array(array) = &child.kind else {
84+
return None;
85+
};
86+
let index = abs_index(*rel_index, array.len()).ok()?;
87+
child = array.get(index)?;
8688
}
8789
}
88-
89-
Self::Subscript(expr, index) => match expr.get(root) {
90-
Some(child) => match child.kind {
91-
ValueKind::Array(ref array) => {
92-
let index = abs_index(index, array.len()).ok()?;
93-
array.get(index)
94-
}
95-
96-
_ => None,
97-
},
98-
99-
_ => None,
100-
},
10190
}
91+
Some(child)
10292
}
10393

10494
pub(crate) fn get_mut_forcibly<'a>(&self, root: &'a mut Value) -> &'a mut Value {
105-
match *self {
106-
Self::Identifier(ref key) => {
107-
if !matches!(root.kind, ValueKind::Table(_)) {
108-
*root = Map::<String, Value>::new().into();
109-
}
110-
let ValueKind::Table(ref mut map) = root.kind else {
111-
unreachable!()
112-
};
113-
114-
map.entry(key.clone())
115-
.or_insert_with(|| Value::new(None, ValueKind::Nil))
116-
}
117-
118-
Self::Child(ref expr, ref key) => {
119-
let child = expr.get_mut_forcibly(root);
120-
121-
if !matches!(child.kind, ValueKind::Table(_)) {
122-
*child = Map::<String, Value>::new().into();
123-
}
124-
let ValueKind::Table(ref mut map) = child.kind else {
125-
unreachable!()
126-
};
127-
128-
map.entry(key.clone())
129-
.or_insert_with(|| Value::new(None, ValueKind::Nil))
130-
}
131-
132-
Self::Subscript(ref expr, index) => {
133-
let child = expr.get_mut_forcibly(root);
95+
if !matches!(root.kind, ValueKind::Table(_)) {
96+
*root = Map::<String, Value>::new().into();
97+
}
98+
let ValueKind::Table(map) = &mut root.kind else {
99+
unreachable!()
100+
};
101+
let mut child = map
102+
.entry(self.root.clone())
103+
.or_insert_with(|| Value::new(None, ValueKind::Nil));
104+
for postfix in &self.postfix {
105+
match postfix {
106+
Postfix::Key(key) => {
107+
if !matches!(child.kind, ValueKind::Table(_)) {
108+
*child = Map::<String, Value>::new().into();
109+
}
110+
let ValueKind::Table(ref mut map) = child.kind else {
111+
unreachable!()
112+
};
134113

135-
if !matches!(child.kind, ValueKind::Array(_)) {
136-
*child = Vec::<Value>::new().into();
114+
child = map
115+
.entry(key.clone())
116+
.or_insert_with(|| Value::new(None, ValueKind::Nil));
137117
}
138-
let ValueKind::Array(ref mut array) = child.kind else {
139-
unreachable!()
140-
};
141-
142-
let uindex = match abs_index(index, array.len()) {
143-
Ok(uindex) => {
144-
if uindex >= array.len() {
145-
array.resize(uindex + 1, Value::new(None, ValueKind::Nil));
146-
}
147-
uindex
148-
}
149-
Err(insertion) => {
150-
array.splice(
151-
0..0,
152-
(0..insertion).map(|_| Value::new(None, ValueKind::Nil)),
153-
);
154-
0
118+
Postfix::Index(rel_index) => {
119+
if !matches!(child.kind, ValueKind::Array(_)) {
120+
*child = Vec::<Value>::new().into();
155121
}
156-
};
122+
let ValueKind::Array(ref mut array) = child.kind else {
123+
unreachable!()
124+
};
125+
126+
let uindex = match abs_index(*rel_index, array.len()) {
127+
Ok(uindex) => {
128+
if uindex >= array.len() {
129+
array.resize(uindex + 1, Value::new(None, ValueKind::Nil));
130+
}
131+
uindex
132+
}
133+
Err(insertion) => {
134+
array.splice(
135+
0..0,
136+
(0..insertion).map(|_| Value::new(None, ValueKind::Nil)),
137+
);
138+
0
139+
}
140+
};
157141

158-
&mut array[uindex]
142+
child = &mut array[uindex];
143+
}
159144
}
160145
}
146+
child
161147
}
162148

163149
pub(crate) fn set(&self, root: &mut Value, value: Value) {

src/path/parser.rs

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,30 @@ use winnow::token::any;
1717
use winnow::token::take_while;
1818

1919
use crate::path::Expression;
20+
use crate::path::Postfix;
2021

2122
pub(crate) fn from_str(input: &str) -> Result<Expression, ParseError<&str, ContextError>> {
2223
path.parse(input)
2324
}
2425

2526
fn path(i: &mut &str) -> PResult<Expression> {
2627
let root = ident.parse_next(i)?;
27-
let expr = repeat(0.., postfix)
28-
.fold(
29-
|| root.clone(),
30-
|prev, cur| match cur {
31-
Child::Key(k) => Expression::Child(Box::new(prev), k),
32-
Child::Index(k) => Expression::Subscript(Box::new(prev), k),
33-
},
34-
)
35-
.parse_next(i)?;
28+
let postfix = repeat(0.., postfix).parse_next(i)?;
29+
let expr = Expression { root, postfix };
3630
Ok(expr)
3731
}
3832

39-
fn ident(i: &mut &str) -> PResult<Expression> {
40-
raw_ident.map(Expression::Identifier).parse_next(i)
41-
}
42-
43-
fn postfix(i: &mut &str) -> PResult<Child> {
33+
fn postfix(i: &mut &str) -> PResult<Postfix> {
4434
dispatch! {any;
4535
'[' => cut_err(
4636
seq!(
47-
integer.map(Child::Index),
37+
integer.map(Postfix::Index),
4838
_: ']'.context(StrContext::Expected(StrContextValue::CharLiteral(']'))),
4939
)
5040
.map(|(i,)| i)
5141
.context(StrContext::Label("subscript"))
5242
),
53-
'.' => cut_err(raw_ident.map(Child::Key)),
43+
'.' => cut_err(ident.map(Postfix::Key)),
5444
_ => cut_err(
5545
fail
5646
.context(StrContext::Label("postfix"))
@@ -61,14 +51,9 @@ fn postfix(i: &mut &str) -> PResult<Child> {
6151
.parse_next(i)
6252
}
6353

64-
enum Child {
65-
Key(String),
66-
Index(isize),
67-
}
68-
69-
fn raw_ident(i: &mut &str) -> PResult<String> {
54+
fn ident(i: &mut &str) -> PResult<String> {
7055
take_while(1.., ('a'..='z', 'A'..='Z', '0'..='9', '_', '-'))
71-
.map(ToString::to_string)
56+
.map(ToOwned::to_owned)
7257
.context(StrContext::Label("identifier"))
7358
.context(StrContext::Expected(StrContextValue::Description(
7459
"ASCII alphanumeric",
@@ -104,9 +89,10 @@ mod test {
10489
assert_data_eq!(
10590
parsed.to_debug(),
10691
str![[r#"
107-
Identifier(
108-
"abcd",
109-
)
92+
Expression {
93+
root: "abcd",
94+
postfix: [],
95+
}
11096
11197
"#]]
11298
);
@@ -118,9 +104,10 @@ Identifier(
118104
assert_data_eq!(
119105
parsed.to_debug(),
120106
str![[r#"
121-
Identifier(
122-
"abcd-efgh",
123-
)
107+
Expression {
108+
root: "abcd-efgh",
109+
postfix: [],
110+
}
124111
125112
"#]]
126113
);
@@ -132,12 +119,14 @@ Identifier(
132119
assert_data_eq!(
133120
parsed.to_debug(),
134121
str![[r#"
135-
Child(
136-
Identifier(
137-
"abcd",
138-
),
139-
"efgh",
140-
)
122+
Expression {
123+
root: "abcd",
124+
postfix: [
125+
Key(
126+
"efgh",
127+
),
128+
],
129+
}
141130
142131
"#]]
143132
);
@@ -146,15 +135,17 @@ Child(
146135
assert_data_eq!(
147136
parsed.to_debug(),
148137
str![[r#"
149-
Child(
150-
Child(
151-
Identifier(
152-
"abcd",
138+
Expression {
139+
root: "abcd",
140+
postfix: [
141+
Key(
142+
"efgh",
143+
),
144+
Key(
145+
"ijkl",
153146
),
154-
"efgh",
155-
),
156-
"ijkl",
157-
)
147+
],
148+
}
158149
159150
"#]]
160151
);
@@ -166,12 +157,14 @@ Child(
166157
assert_data_eq!(
167158
parsed.to_debug(),
168159
str![[r#"
169-
Subscript(
170-
Identifier(
171-
"abcd",
172-
),
173-
12,
174-
)
160+
Expression {
161+
root: "abcd",
162+
postfix: [
163+
Index(
164+
12,
165+
),
166+
],
167+
}
175168
176169
"#]]
177170
);
@@ -183,12 +176,14 @@ Subscript(
183176
assert_data_eq!(
184177
parsed.to_debug(),
185178
str![[r#"
186-
Subscript(
187-
Identifier(
188-
"abcd",
189-
),
190-
-1,
191-
)
179+
Expression {
180+
root: "abcd",
181+
postfix: [
182+
Index(
183+
-1,
184+
),
185+
],
186+
}
192187
193188
"#]]
194189
);

0 commit comments

Comments
 (0)