Skip to content

Commit 4769257

Browse files
sgvictorinoNotTheDr01ds
authored andcommitted
correctly parse table literals as lists (nushell#14226)
# User-Facing Changes Table literal arguments to list parameters are now correctly parsed: ```diff def a [l: list<any>] { $l | to nuon }; a [[a]; [2]] -[[a]] +[[a]; [2]] ```
1 parent 9d13a6b commit 4769257

File tree

2 files changed

+34
-68
lines changed

2 files changed

+34
-68
lines changed

crates/nu-parser/src/parser.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,7 +2312,7 @@ pub fn parse_full_cell_path(
23122312
} else if bytes.starts_with(b"[") {
23132313
trace!("parsing: table head of full cell path");
23142314

2315-
let output = parse_table_expression(working_set, head.span);
2315+
let output = parse_table_expression(working_set, head.span, &SyntaxShape::Any);
23162316

23172317
tokens.next();
23182318

@@ -4120,7 +4120,11 @@ fn parse_table_row(
41204120
.map(|exprs| (exprs, span))
41214121
}
41224122

4123-
fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression {
4123+
fn parse_table_expression(
4124+
working_set: &mut StateWorkingSet,
4125+
span: Span,
4126+
list_element_shape: &SyntaxShape,
4127+
) -> Expression {
41244128
let bytes = working_set.get_span_contents(span);
41254129
let inner_span = {
41264130
let start = if bytes.starts_with(b"[") {
@@ -4149,13 +4153,13 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
41494153
// Check that we have all arguments first, before trying to parse the first
41504154
// in order to avoid exponential parsing time
41514155
let [first, second, rest @ ..] = &tokens[..] else {
4152-
return parse_list_expression(working_set, span, &SyntaxShape::Any);
4156+
return parse_list_expression(working_set, span, list_element_shape);
41534157
};
41544158
if !working_set.get_span_contents(first.span).starts_with(b"[")
41554159
|| second.contents != TokenContents::Semicolon
41564160
|| rest.is_empty()
41574161
{
4158-
return parse_list_expression(working_set, span, &SyntaxShape::Any);
4162+
return parse_list_expression(working_set, span, list_element_shape);
41594163
};
41604164
let head = parse_table_row(working_set, first.span);
41614165

@@ -4771,7 +4775,7 @@ pub fn parse_value(
47714775
}
47724776
SyntaxShape::List(elem) => {
47734777
if bytes.starts_with(b"[") {
4774-
parse_list_expression(working_set, span, elem)
4778+
parse_table_expression(working_set, span, elem)
47754779
} else {
47764780
working_set.error(ParseError::Expected("list", span));
47774781

@@ -4780,7 +4784,7 @@ pub fn parse_value(
47804784
}
47814785
SyntaxShape::Table(_) => {
47824786
if bytes.starts_with(b"[") {
4783-
parse_table_expression(working_set, span)
4787+
parse_table_expression(working_set, span, &SyntaxShape::Any)
47844788
} else {
47854789
working_set.error(ParseError::Expected("table", span));
47864790

tests/repl/test_signatures.rs

Lines changed: 24 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -271,68 +271,30 @@ fn table_annotations_none() -> TestResult {
271271
run_test(input, expected)
272272
}
273273

274-
#[test]
275-
fn table_annotations() -> TestResult {
276-
let input = "def run [t: table<age: int>] { $t }; run [[age]; [3]] | describe";
277-
let expected = "table<age: int>";
278-
run_test(input, expected)
279-
}
280-
281-
#[test]
282-
fn table_annotations_two_types() -> TestResult {
283-
let input = "\
284-
def run [t: table<name: string age: int>] { $t };
285-
run [[name, age]; [nushell, 3]] | describe";
286-
let expected = "table<name: string, age: int>";
287-
run_test(input, expected)
288-
}
289-
290-
#[test]
291-
fn table_annotations_two_types_comma_sep() -> TestResult {
292-
let input = "\
293-
def run [t: table<name: string, age: int>] { $t };
294-
run [[name, age]; [nushell, 3]] | describe";
295-
let expected = "table<name: string, age: int>";
296-
run_test(input, expected)
297-
}
298-
299-
#[test]
300-
fn table_annotations_key_with_no_type() -> TestResult {
301-
let input = "def run [t: table<name>] { $t }; run [[name]; [nushell]] | describe";
302-
let expected = "table<name: string>";
303-
run_test(input, expected)
304-
}
305-
306-
#[test]
307-
fn table_annotations_two_types_one_with_no_type() -> TestResult {
308-
let input = "\
309-
def run [t: table<name: string, age>] { $t };
310-
run [[name, age]; [nushell, 3]] | describe";
311-
let expected = "table<name: string, age: int>";
312-
run_test(input, expected)
313-
}
314-
315-
#[test]
316-
fn table_annotations_two_types_both_with_no_types() -> TestResult {
317-
let input = "\
318-
def run [t: table<name, age>] { $t };
319-
run [[name, age]; [nushell, 3]] | describe";
320-
let expected = "table<name: string, age: int>";
321-
run_test(input, expected)
322-
}
323-
324-
#[test]
325-
fn table_annotations_type_inference_1() -> TestResult {
326-
let input = "def run [t: table<age: any>] { $t }; run [[age]; [2wk]] | describe";
327-
let expected = "table<age: duration>";
328-
run_test(input, expected)
329-
}
330-
331-
#[test]
332-
fn table_annotations_type_inference_2() -> TestResult {
333-
let input = "def run [t: table<size>] { $t }; run [[size]; [2mb]] | describe";
334-
let expected = "table<size: filesize>";
335-
run_test(input, expected)
274+
#[rstest]
275+
fn table_annotations(
276+
#[values(true, false)] list_annotation: bool,
277+
#[values(
278+
("age: int", "age: int", "[[age]; [3]]" ),
279+
("name: string age: int", "name: string, age: int", "[[name, age]; [nushell, 3]]" ),
280+
("name: string, age: int", "name: string, age: int", "[[name, age]; [nushell, 3]]" ),
281+
("name", "name: string", "[[name]; [nushell]]"),
282+
("name: string, age", "name: string, age: int", "[[name, age]; [nushell, 3]]"),
283+
("name, age", "name: string, age: int", "[[name, age]; [nushell, 3]]"),
284+
("age: any", "age: duration", "[[age]; [2wk]]"),
285+
("size", "size: filesize", "[[size]; [2mb]]")
286+
)]
287+
record_annotation_data: (&str, &str, &str),
288+
) -> TestResult {
289+
let (record_annotation, inferred_type, data) = record_annotation_data;
290+
291+
let type_annotation = match list_annotation {
292+
true => format!("list<record<{record_annotation}>>"),
293+
false => format!("table<{record_annotation}>"),
294+
};
295+
let input = format!("def run [t: {type_annotation}] {{ $t }}; run {data} | describe");
296+
let expected = format!("table<{inferred_type}>");
297+
run_test(&input, &expected)
336298
}
337299

338300
#[test]

0 commit comments

Comments
 (0)