Skip to content

Commit 4f14418

Browse files
committed
Refactor link handling to support singlet links and update related tests
1 parent dab82ba commit 4f14418

File tree

4 files changed

+105
-32
lines changed

4 files changed

+105
-32
lines changed

rust/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod parser;
22

33
use std::fmt;
44

5-
#[derive(Debug, Clone)]
5+
#[derive(Debug, Clone, PartialEq)]
66
pub enum LiNo<T> {
77
Link { id: Option<T>, values: Vec<Self> },
88
Ref(T),

rust/src/parser.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub struct Link {
1818
}
1919

2020
impl Link {
21-
pub fn new_point(id: String) -> Self {
21+
pub fn new_singlet(id: String) -> Self {
2222
Link {
2323
id: Some(id),
2424
values: vec![],
@@ -75,7 +75,7 @@ impl ParserState {
7575
}
7676

7777
pub fn check_indentation(&self, indent: usize) -> bool {
78-
indent == self.current_indentation()
78+
indent >= self.current_indentation()
7979
}
8080
}
8181

@@ -140,26 +140,12 @@ fn eol(input: &str) -> IResult<&str, &str> {
140140
)).parse(input)
141141
}
142142

143-
fn point_link(input: &str) -> IResult<&str, Link> {
144-
reference.map(Link::new_point).parse(input)
145-
}
146143

147-
fn single_line_point_link(input: &str) -> IResult<&str, Link> {
148-
preceded(horizontal_whitespace, point_link).parse(input)
149-
}
150-
151-
fn multi_line_point_link(input: &str) -> IResult<&str, Link> {
152-
delimited(
153-
(char('('), whitespace),
154-
point_link,
155-
(whitespace, char(')'))
156-
).parse(input)
157-
}
158144

159145
fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
160146
alt((
161147
|i| multi_line_any_link(i, state),
162-
reference.map(Link::new_point),
148+
reference.map(Link::new_singlet),
163149
)).parse(input)
164150
}
165151

@@ -215,7 +201,13 @@ fn multi_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str,
215201

216202
fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
217203
(|i| single_line_values(i, state))
218-
.map(Link::new_value)
204+
.map(|values| {
205+
if values.len() == 1 && values[0].id.is_some() && values[0].values.is_empty() && values[0].children.is_empty() {
206+
Link::new_singlet(values[0].id.clone().unwrap())
207+
} else {
208+
Link::new_value(values)
209+
}
210+
})
219211
.parse(input)
220212
}
221213

@@ -225,13 +217,18 @@ fn multi_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a
225217
|i| multi_line_values(i, state),
226218
whitespace,
227219
char(')')
228-
).map(|(_, values, _, _)| Link::new_value(values))
220+
).map(|(_, values, _, _)| {
221+
if values.len() == 1 && values[0].id.is_some() && values[0].values.is_empty() && values[0].children.is_empty() {
222+
Link::new_singlet(values[0].id.clone().unwrap())
223+
} else {
224+
Link::new_value(values)
225+
}
226+
})
229227
.parse(input)
230228
}
231229

232230
fn multi_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
233231
alt((
234-
multi_line_point_link,
235232
|i| multi_line_value_link(i, state),
236233
|i| multi_line_link(i, state),
237234
)).parse(input)
@@ -240,7 +237,6 @@ fn multi_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a s
240237
fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
241238
alt((
242239
terminated(|i| single_line_link(i, state), eol),
243-
terminated(single_line_point_link, eol),
244240
terminated(|i| single_line_value_link(i, state), eol),
245241
)).parse(input)
246242
}

rust/tests/edge_case_parser_tests.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ fn test_all_features_test() {
4949
let result = parse_lino(input);
5050
assert!(result.is_err());
5151

52-
// Test point link
53-
let input = "(point)";
52+
// Test singlet link
53+
let input = "(singlet)";
5454
let result = parse_lino(input);
5555
assert!(result.is_ok());
56+
let parsed = result.unwrap();
57+
if let LiNo::Ref(id) = parsed {
58+
assert_eq!(id, "singlet");
59+
}
5660

5761
// Test value link
5862
let input = "(value1 value2 value3)";
@@ -119,6 +123,69 @@ fn test_empty_links_test() {
119123
assert!(result.is_ok());
120124
}
121125

126+
#[test]
127+
fn test_singlet_links() {
128+
// Test singlet (1)
129+
let input = "(1)";
130+
let result = parse_lino(input);
131+
assert!(result.is_ok());
132+
let parsed = result.unwrap();
133+
if let LiNo::Ref(id) = parsed {
134+
assert_eq!(id, "1");
135+
}
136+
137+
// Test (1 2)
138+
let input = "(1 2)";
139+
let result = parse_lino(input);
140+
assert!(result.is_ok());
141+
let parsed = result.unwrap();
142+
if let LiNo::Link { id, values } = parsed {
143+
assert!(id.is_none());
144+
assert_eq!(values.len(), 1);
145+
if let LiNo::Link { id, values } = &values[0] {
146+
assert!(id.is_none());
147+
assert_eq!(values.len(), 2);
148+
assert_eq!(values[0], LiNo::Ref("1".to_string()));
149+
assert_eq!(values[1], LiNo::Ref("2".to_string()));
150+
}
151+
}
152+
153+
// Test (1 2 3)
154+
let input = "(1 2 3)";
155+
let result = parse_lino(input);
156+
assert!(result.is_ok());
157+
let parsed = result.unwrap();
158+
if let LiNo::Link { id, values } = parsed {
159+
assert!(id.is_none());
160+
assert_eq!(values.len(), 1);
161+
if let LiNo::Link { id, values } = &values[0] {
162+
assert!(id.is_none());
163+
assert_eq!(values.len(), 3);
164+
assert_eq!(values[0], LiNo::Ref("1".to_string()));
165+
assert_eq!(values[1], LiNo::Ref("2".to_string()));
166+
assert_eq!(values[2], LiNo::Ref("3".to_string()));
167+
}
168+
}
169+
170+
// Test (1 2 3 4)
171+
let input = "(1 2 3 4)";
172+
let result = parse_lino(input);
173+
assert!(result.is_ok());
174+
let parsed = result.unwrap();
175+
if let LiNo::Link { id, values } = parsed {
176+
assert!(id.is_none());
177+
assert_eq!(values.len(), 1);
178+
if let LiNo::Link { id, values } = &values[0] {
179+
assert!(id.is_none());
180+
assert_eq!(values.len(), 4);
181+
assert_eq!(values[0], LiNo::Ref("1".to_string()));
182+
assert_eq!(values[1], LiNo::Ref("2".to_string()));
183+
assert_eq!(values[2], LiNo::Ref("3".to_string()));
184+
assert_eq!(values[3], LiNo::Ref("4".to_string()));
185+
}
186+
}
187+
}
188+
122189
#[test]
123190
fn test_invalid_input() {
124191
let input = "(invalid";

rust/tests/single_line_parser_tests.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ fn parse_simple_reference() {
118118
let input = "test";
119119
let result = parse_lino(input).unwrap();
120120
assert!(result.is_link());
121-
if let LiNo::Link { values, .. } = &result {
121+
if let LiNo::Link { id, values } = &result {
122+
assert!(id.is_none());
122123
assert_eq!(values.len(), 1);
123124
if let LiNo::Ref(id) = &values[0] {
124125
assert_eq!(id, "test");
@@ -201,10 +202,17 @@ fn test_link_without_id_multi_line() {
201202
}
202203

203204
#[test]
204-
fn test_point_link() {
205-
let input = "(point)";
206-
let result = parse_lino(input);
207-
assert!(result.is_ok());
205+
fn test_singlet_link() {
206+
let input = "(singlet)";
207+
let result = parse_lino(input).unwrap();
208+
assert!(result.is_link());
209+
if let LiNo::Link { id, values } = &result {
210+
assert!(id.is_none());
211+
assert_eq!(values.len(), 1);
212+
if let LiNo::Ref(ref_id) = &values[0] {
213+
assert_eq!(ref_id, "singlet");
214+
}
215+
}
208216
}
209217

210218
#[test]
@@ -284,10 +292,12 @@ fn test_quoted_reference() {
284292
}
285293

286294
#[test]
287-
fn test_point_link_parser() {
288-
let result = parse_document("(point)").unwrap();
295+
fn test_singlet_link_parser() {
296+
let result = parse_document("(singlet)").unwrap();
289297
assert_eq!(result.1.len(), 1);
290-
assert_eq!(result.1[0].id, Some("point".to_string()));
298+
assert_eq!(result.1[0].id, Some("singlet".to_string()));
299+
assert_eq!(result.1[0].values.len(), 0);
300+
assert_eq!(result.1[0].children.len(), 0);
291301
}
292302

293303
#[test]

0 commit comments

Comments
 (0)