fn classify_pipeline(
    lite_pipeline: &LitePipeline,
    registry: &dyn SignatureRegistry,
) -> (ClassifiedPipeline, Option<ParseError>) {
    let mut commands = Commands::new(lite_pipeline.span());
    let mut error = None;

    let mut iter = lite_pipeline.commands.iter().peekable();
    while let Some(lite_cmd) = iter.next() {
        if lite_cmd.parts.is_empty() {
            continue;
        }
        if lite_cmd.parts[0].item.starts_with('^') {
            let name = lite_cmd.parts[0]
                .clone()
                .map(|v| v.chars().skip(1).collect::<String>());
            // TODO this is the same as the `else` branch below, only the name differs. Find a way
            //      to share this functionality.
            let mut args = vec![];

            let (name, err) = parse_arg(SyntaxShape::String, registry, &name);
            let name_span = name.span;
            if error.is_none() {
                error = err;
            }
            args.push(name);

            for lite_arg in &lite_cmd.parts[1..] {
                let (expr, err) = parse_external_arg(registry, lite_arg);
                if error.is_none() {
                    error = err;
                }
                args.push(expr);
            }

            commands.push(ClassifiedCommand::Internal(InternalCommand {
                name: "run_external".to_string(),
                name_span,
                args: hir::Call {
                    head: Box::new(SpannedExpression {
                        expr: Expression::string("run_external".to_string()),
                        span: name_span,
                    }),
                    positional: Some(args),
                    named: None,
                    span: name_span,
                    external_redirection: if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    },
                },
            }))
        } else if lite_cmd.parts[0].item == "=" {
            let expr = if lite_cmd.parts.len() > 1 {
                let (_, expr, err) =
                    parse_math_expression(0, &lite_cmd.parts[1..], registry, false);
                error = error.or(err);
                expr
            } else {
                error = error.or_else(|| {
                    Some(ParseError::argument_error(
                        lite_cmd.parts[0].clone(),
                        ArgumentError::MissingMandatoryPositional("an expression".into()),
                    ))
                });
                garbage(lite_cmd.span())
            };
            commands.push(ClassifiedCommand::Expr(Box::new(expr)))
        } else {
            if lite_cmd.parts.len() > 1 {
                // Check if it's a sub-command
                if let Some(signature) = registry.get(&format!(
                    "{} {}",
                    lite_cmd.parts[0].item, lite_cmd.parts[1].item
                )) {
                    let (mut internal_command, err) =
                        parse_internal_command(&lite_cmd, registry, &signature, 1);

                    error = error.or(err);
                    internal_command.args.external_redirection = if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    };
                    commands.push(ClassifiedCommand::Internal(internal_command));
                    continue;
                }
            }

            // Check if it's an internal command
            if let Some(signature) = registry.get(&lite_cmd.parts[0].item) {
                let (mut internal_command, err) =
                    parse_internal_command(&lite_cmd, registry, &signature, 0);

                error = error.or(err);
                internal_command.args.external_redirection = if iter.peek().is_none() {
                    ExternalRedirection::None
                } else {
                    ExternalRedirection::Stdout
                };
                commands.push(ClassifiedCommand::Internal(internal_command));
                continue;
            }

            let name = lite_cmd.parts[0].clone().map(|v| {
                let trimmed = trim_quotes(&v);
                expand_path(&trimmed).to_string()
            });

            let mut args = vec![];

            let (name, err) = parse_arg(SyntaxShape::String, registry, &name);
            let name_span = name.span;
            if error.is_none() {
                error = err;
            }
            args.push(name);

            for lite_arg in &lite_cmd.parts[1..] {
                let (expr, err) = parse_external_arg(registry, lite_arg);
                if error.is_none() {
                    error = err;
                }
                args.push(expr);
            }

            commands.push(ClassifiedCommand::Internal(InternalCommand {
                name: "run_external".to_string(),
                name_span,
                args: hir::Call {
                    head: Box::new(SpannedExpression {
                        expr: Expression::string("run_external".to_string()),
                        span: name_span,
                    }),
                    positional: Some(args),
                    named: None,
                    span: name_span,
                    external_redirection: if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    },
                },
            }))
        }
    }

    (ClassifiedPipeline::new(commands), error)
}
/// Convert a lite-ly parsed pipeline into a fully classified pipeline, ready to be evaluated.
/// This conversion does error-recovery, so the result is allowed to be lossy. A lossy unit is designated as garbage.
/// Errors are returned as part of a side-car error rather than a Result to allow both error and lossy result simultaneously.
Convert a lite-ly parsed pipeline into a fully classified pipeline, ready to be evaluated.
This conversion does error-recovery, so the result is allowed to be lossy. A lossy unit is designated as garbage.
Errors are returned as part of a side-car error rather than a Result to allow both error and lossy result simultaneously.
Convert a lite - ly parsed pipeline into a fully classified pipeline ready to be evaluated . This conversion does error - recovery so the result is allowed to be lossy . A lossy unit is designated as garbage . Errors are returned as part of a side - car error rather than a Result to allow both error and lossy result simultaneously .
fn classify_pipeline(
    lite_pipeline: &LitePipeline,
    registry: &dyn SignatureRegistry,
) -> (ClassifiedPipeline, Option<ParseError>) {
    let mut commands = Commands::new(lite_pipeline.span());
    let mut error = None;
    let mut iter = lite_pipeline.commands.iter().peekable();
    while let Some(lite_cmd) = iter.next() {
        if lite_cmd.parts.is_empty() {
            continue;
        }
        if lite_cmd.parts[0].item.starts_with('^') {
            let name = lite_cmd.parts[0]
                .clone()
                .map(|v| v.chars().skip(1).collect::<String>());
            // TODO this is the same as the `else` branch below, only the name differs. Find a way
            //      to share this functionality.
            let mut args = vec![];
            let (name, err) = parse_arg(SyntaxShape::String, registry, &name);
            let name_span = name.span;
            if error.is_none() {
                error = err;
            }
            args.push(name);
            for lite_arg in &lite_cmd.parts[1..] {
                let (expr, err) = parse_external_arg(registry, lite_arg);
                if error.is_none() {
                    error = err;
                }
                args.push(expr);
            }
            commands.push(ClassifiedCommand::Internal(InternalCommand {
                name: "run_external".to_string(),
                name_span,
                args: hir::Call {
                    head: Box::new(SpannedExpression {
                        expr: Expression::string("run_external".to_string()),
                        span: name_span,
                    }),
                    positional: Some(args),
                    named: None,
                    span: name_span,
                    external_redirection: if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    },
                },
            }))
        } else if lite_cmd.parts[0].item == "=" {
            let expr = if lite_cmd.parts.len() > 1 {
                let (_, expr, err) =
                    parse_math_expression(0, &lite_cmd.parts[1..], registry, false);
                error = error.or(err);
                expr
            } else {
                error = error.or_else(|| {
                    Some(ParseError::argument_error(
                        lite_cmd.parts[0].clone(),
                        ArgumentError::MissingMandatoryPositional("an expression".into()),
                    ))
                });
                garbage(lite_cmd.span())
            };
            commands.push(ClassifiedCommand::Expr(Box::new(expr)))
        } else {
            if lite_cmd.parts.len() > 1 {
                // Check if it's a sub-command
                if let Some(signature) = registry.get(&format!(
                    "{} {}",
                    lite_cmd.parts[0].item, lite_cmd.parts[1].item
                )) {
                    let (mut internal_command, err) =
                        parse_internal_command(&lite_cmd, registry, &signature, 1);
                    error = error.or(err);
                    internal_command.args.external_redirection = if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    };
                    commands.push(ClassifiedCommand::Internal(internal_command));
                    continue;
                }
            }
            // Check if it's an internal command
            if let Some(signature) = registry.get(&lite_cmd.parts[0].item) {
                let (mut internal_command, err) =
                    parse_internal_command(&lite_cmd, registry, &signature, 0);
                error = error.or(err);
                internal_command.args.external_redirection = if iter.peek().is_none() {
                    ExternalRedirection::None
                } else {
                    ExternalRedirection::Stdout
                };
                commands.push(ClassifiedCommand::Internal(internal_command));
                continue;
            }
            let name = lite_cmd.parts[0].clone().map(|v| {
                let trimmed = trim_quotes(&v);
                expand_path(&trimmed).to_string()
            });
            let mut args = vec![];
            let (name, err) = parse_arg(SyntaxShape::String, registry, &name);
            let name_span = name.span;
            if error.is_none() {
                error = err;
            }
            args.push(name);
            for lite_arg in &lite_cmd.parts[1..] {
                let (expr, err) = parse_external_arg(registry, lite_arg);
                if error.is_none() {
                    error = err;
                }
                args.push(expr);
            }
            commands.push(ClassifiedCommand::Internal(InternalCommand {
                name: "run_external".to_string(),
                name_span,
                args: hir::Call {
                    head: Box::new(SpannedExpression {
                        expr: Expression::string("run_external".to_string()),
                        span: name_span,
                    }),
                    positional: Some(args),
                    named: None,
                    span: name_span,
                    external_redirection: if iter.peek().is_none() {
                        ExternalRedirection::None
                    } else {
                        ExternalRedirection::Stdout
                    },
                },
            }))
        }
    }
    (ClassifiedPipeline::new(commands), error)
}
fn classify_pipeline ( lite_pipeline : & LitePipeline , registry : & dyn SignatureRegistry , ) -> ( ClassifiedPipeline , Option < ParseError > ) { let mut commands = Commands :: new ( lite_pipeline . span ( ) ) ; let mut error = None ; let mut iter = lite_pipeline . commands . iter ( ) . peekable ( ) ; while let Some ( lite_cmd ) = iter . next ( ) { if lite_cmd . parts . is_empty ( ) { continue ; } if lite_cmd . parts [ 0 ] . item . starts_with ( '^' ) { let name = lite_cmd . parts [ 0 ] . clone ( ) . map ( | v | v . chars ( ) . skip ( 1 ) . collect :: < String > ( ) ) ; // TODO this is the same as the `else` branch below, only the name differs. Find a way //      to share this functionality. let mut args = vec ! [ ] ; let ( name , err ) = parse_arg ( SyntaxShape :: String , registry , & name ) ; let name_span = name . span ; if error . is_none ( ) { error = err ; } args . push ( name ) ; for lite_arg in & lite_cmd . parts [ 1 .. ] { let ( expr , err ) = parse_external_arg ( registry , lite_arg ) ; if error . is_none ( ) { error = err ; } args . push ( expr ) ; } commands . push ( ClassifiedCommand :: Internal ( InternalCommand { name : " " . to_string ( ) , name_span , args : hir :: Call { head : Box :: new ( SpannedExpression { expr : Expression :: string ( " " . to_string ( ) ) , span : name_span , } ) , positional : Some ( args ) , named : None , span : name_span , external_redirection : if iter . peek ( ) . is_none ( ) { ExternalRedirection :: None } else { ExternalRedirection :: Stdout } , } , } ) ) } else if lite_cmd . parts [ 0 ] . item == " " { let expr = if lite_cmd . parts . len ( ) > 1 { let ( _ , expr , err ) = parse_math_expression ( 0 , & lite_cmd . parts [ 1 .. ] , registry , false ) ; error = error . or ( err ) ; expr } else { error = error . or_else ( | | { Some ( ParseError :: argument_error ( lite_cmd . parts [ 0 ] . clone ( ) , ArgumentError :: MissingMandatoryPositional ( " " . into ( ) ) , ) ) } ) ; garbage ( lite_cmd . span ( ) ) } ; commands . push ( ClassifiedCommand :: Expr ( Box :: new ( expr ) ) ) } else { if lite_cmd . parts . len ( ) > 1 { // Check if it's a sub-command if let Some ( signature ) = registry . get ( & format ! ( " " lite_cmd parts [ 0 ] item lite_cmd parts [ 1 ] item ) ) { let ( mut internal_command , err ) = parse_internal_command ( & lite_cmd , registry , & signature , 1 ) ; error = error . or ( err ) ; internal_command . args . external_redirection = if iter . peek ( ) . is_none ( ) { ExternalRedirection :: None } else { ExternalRedirection :: Stdout } ; commands . push ( ClassifiedCommand :: Internal ( internal_command ) ) ; continue ; } } // Check if it's an internal command if let Some ( signature ) = registry . get ( & lite_cmd . parts [ 0 ] . item ) { let ( mut internal_command , err ) = parse_internal_command ( & lite_cmd , registry , & signature , 0 ) ; error = error . or ( err ) ; internal_command . args . external_redirection = if iter . peek ( ) . is_none ( ) { ExternalRedirection :: None } else { ExternalRedirection :: Stdout } ; commands . push ( ClassifiedCommand :: Internal ( internal_command ) ) ; continue ; } let name = lite_cmd . parts [ 0 ] . clone ( ) . map ( | v | { let trimmed = trim_quotes ( & v ) ; expand_path ( & trimmed ) . to_string ( ) } ) ; let mut args = vec ! [ ] ; let ( name , err ) = parse_arg ( SyntaxShape :: String , registry , & name ) ; let name_span = name . span ; if error . is_none ( ) { error = err ; } args . push ( name ) ; for lite_arg in & lite_cmd . parts [ 1 .. ] { let ( expr , err ) = parse_external_arg ( registry , lite_arg ) ; if error . is_none ( ) { error = err ; } args . push ( expr ) ; } commands . push ( ClassifiedCommand :: Internal ( InternalCommand { name : " " . to_string ( ) , name_span , args : hir :: Call { head : Box :: new ( SpannedExpression { expr : Expression :: string ( " " . to_string ( ) ) , span : name_span , } ) , positional : Some ( args ) , named : None , span : name_span , external_redirection : if iter . peek ( ) . is_none ( ) { ExternalRedirection :: None } else { ExternalRedirection :: Stdout } , } , } ) ) } } ( ClassifiedPipeline :: new ( commands ) , error ) }
Convert a lite-ly parsed pipeline into a fully classified pipeline, ready to be evaluated.
Convert a lite - ly parsed pipeline into a fully classified pipeline ready to be evaluated .
lite_pipeline
&LitePipeline
registry
&dyn SignatureRegistry
lite_pipeline
&LitePipeline
registry
&dyn SignatureRegistry