Repository: nushell/nushell
File: crates/nu-parser/src/parser.rs (Rust)

Code before:
    let (tokens, _) = lex(bytes, span.start + 1, &[b'\r', b'\n', b'\t'], &[b':'], true);

    let second_token = tokens
        .first()
        .map(|token| working_set.get_span_contents(token.span));

    let second_token_contents = tokens.first().map(|token| token.contents);

    let third_token = tokens
        .get(1)
        .map(|token| working_set.get_span_contents(token.span));

    if second_token.is_none() {
        // If we're empty, that means an empty record or closure
        if matches!(shape, SyntaxShape::Closure(_)) {
            parse_closure_expression(working_set, shape, span)
        } else if matches!(shape, SyntaxShape::Block) {
            parse_block_expression(working_set, span)
        } else if matches!(shape, SyntaxShape::MatchBlock) {
            parse_match_block_expression(working_set, span)
        } else {
            parse_record(working_set, span)
        }
    } else if matches!(shape, SyntaxShape::Block) {
        parse_block_expression(working_set, span)
    } else if matches!(shape, SyntaxShape::MatchBlock) {
        parse_match_block_expression(working_set, span)
    } else if matches!(second_token_contents, Some(TokenContents::Pipe))
        || matches!(second_token_contents, Some(TokenContents::PipePipe))
    {
        parse_closure_expression(working_set, shape, span)
    } else if matches!(third_token, Some(b":")) {
        parse_full_cell_path(working_set, None, span)
    } else if matches!(shape, SyntaxShape::Closure(_)) {
        parse_closure_expression(working_set, shape, span)
    } else if second_token.is_some_and(|c| {
        c.len() > 3 && c.starts_with(b"...") && (c[3] == b'$' || c[3] == b'{' || c[3] == b'(')
    }) {
        parse_record(working_set, span)
    } else if matches!(shape, SyntaxShape::Any) {
        parse_closure_expression(working_set, shape, span)
    } else {
        working_set.error(ParseError::ExpectedWithStringMsg(
            format!("non-block value: {shape}"),
            span,
        ));

        Expression::garbage(working_set, span)
    }
}


Review comment (suggestion):
Instead of priorize the SyntaxShape checking for block and MatchBlock, I think it's better to check SyntaxShape before parsing as a closure:
```suggestion
        // when meeting Pipe or PipePipe, it's certain to be a closure
        // But nushell should guide the checking process though SyntaxShape
        if matches!(shape, SyntaxShape::Block) {
            working_set.error(ParseError::ExpectedWithStringMsg(
                "expect a block, but finding a closure".to_string(),
                span,
            ));
            return Expression::garbage(working_set, span);
        }

```

Code after:
    let (tokens, _) = lex(bytes, span.start + 1, &[b'\r', b'\n', b'\t'], &[b':'], true);

    let second_token = tokens
        .first()
        .map(|token| working_set.get_span_contents(token.span));

    let second_token_contents = tokens.first().map(|token| token.contents);

    let third_token = tokens
        .get(1)
        .map(|token| working_set.get_span_contents(token.span));

    if second_token.is_none() {
        // If we're empty, that means an empty record or closure
        if matches!(shape, SyntaxShape::Closure(_)) {
            parse_closure_expression(working_set, shape, span)
        } else if matches!(shape, SyntaxShape::Block) {
            parse_block_expression(working_set, span)
        } else if matches!(shape, SyntaxShape::MatchBlock) {
            parse_match_block_expression(working_set, span)
        } else {
            parse_record(working_set, span)
        }
    } else if matches!(second_token_contents, Some(TokenContents::Pipe))
        || matches!(second_token_contents, Some(TokenContents::PipePipe))
    {
        if matches!(shape, SyntaxShape::Block) {
            working_set.error(ParseError::Mismatch("block".into(), "closure".into(), span));
            return Expression::garbage(working_set, span);
        }
        parse_closure_expression(working_set, shape, span)
    } else if matches!(third_token, Some(b":")) {
        parse_full_cell_path(working_set, None, span)
    } else if matches!(shape, SyntaxShape::Closure(_)) {
        parse_closure_expression(working_set, shape, span)
    } else if matches!(shape, SyntaxShape::Block) {
        parse_block_expression(working_set, span)
    } else if matches!(shape, SyntaxShape::MatchBlock) {
        parse_match_block_expression(working_set, span)
    } else if second_token.is_some_and(|c| {
        c.len() > 3 && c.starts_with(b"...") && (c[3] == b'$' || c[3] == b'{' || c[3] == b'(')
    }) {
        parse_record(working_set, span)
    } else if matches!(shape, SyntaxShape::Any) {
        parse_closure_expression(working_set, shape, span)
    } else {
        working_set.error(ParseError::ExpectedWithStringMsg(
            format!("non-block value: {shape}"),
            span,
        ));