pub fn parse_full_column_path(
    lite_arg: &Spanned<String>,
    registry: &dyn SignatureRegistry,
) -> (SpannedExpression, Option<ParseError>) {
    let mut delimiter = '.';
    let mut inside_delimiter = false;
    let mut output = vec![];
    let mut current_part = String::new();
    let mut start_index = 0;
    let mut last_index = 0;
    let mut error = None;

    let mut head = None;

    for (idx, c) in lite_arg.item.char_indices() {
        last_index = idx;
        if inside_delimiter {
            if c == delimiter {
                inside_delimiter = false;
            }
        } else if c == '(' {
            inside_delimiter = true;
            delimiter = ')';
        } else if c == '\'' || c == '"' {
            inside_delimiter = true;
            delimiter = c;
        } else if c == '.' {
            let part_span = Span::new(
                lite_arg.span.start() + start_index,
                lite_arg.span.start() + idx,
            );

            if head.is_none() && current_part.starts_with("$(") && current_part.ends_with(')') {
                let (invoc, err) =
                    parse_invocation(&current_part.clone().spanned(part_span), registry);
                if error.is_none() {
                    error = err;
                }
                head = Some(invoc.expr);
            } else if head.is_none() && current_part.starts_with('$') {
                // We have the variable head
                head = Some(Expression::variable(current_part.clone(), part_span))
            } else if let Ok(row_number) = current_part.parse::<u64>() {
                output.push(
                    UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
                );
            } else {
                let current_part = trim_quotes(&current_part);
                output.push(
                    UnspannedPathMember::String(current_part.clone()).into_path_member(part_span),
                );
            }
            current_part.clear();
            // Note: I believe this is safe because of the delimiter we're using, but if we get fancy with
            // unicode we'll need to change this
            start_index = idx + '.'.len_utf8();
            continue;
        }
        current_part.push(c);
    }

    if !current_part.is_empty() {
        let part_span = Span::new(
            lite_arg.span.start() + start_index,
            lite_arg.span.start() + last_index + 1,
        );

        if head.is_none() {
            if current_part.starts_with("$(") && current_part.ends_with(')') {
                let (invoc, err) = parse_invocation(&current_part.spanned(part_span), registry);
                if error.is_none() {
                    error = err;
                }
                head = Some(invoc.expr);
            } else if current_part.starts_with('$') {
                head = Some(Expression::variable(current_part, lite_arg.span));
            } else if let Ok(row_number) = current_part.parse::<u64>() {
                output.push(
                    UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
                );
            } else {
                let current_part = trim_quotes(&current_part);
                output.push(UnspannedPathMember::String(current_part).into_path_member(part_span));
            }
        } else if let Ok(row_number) = current_part.parse::<u64>() {
            output.push(
                UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
            );
        } else {
            let current_part = trim_quotes(&current_part);
            output.push(UnspannedPathMember::String(current_part).into_path_member(part_span));
        }
    }

    if let Some(head) = head {
        (
            SpannedExpression::new(
                Expression::path(SpannedExpression::new(head, lite_arg.span), output),
                lite_arg.span,
            ),
            error,
        )
    } else {
        (
            SpannedExpression::new(
                Expression::path(
                    SpannedExpression::new(
                        Expression::variable("$it".into(), lite_arg.span),
                        lite_arg.span,
                    ),
                    output,
                ),
                lite_arg.span,
            ),
            error,
        )
    }
}
/// Parses a column path, adding in the preceding reference to $it if it's elided
Parses a column path, adding in the preceding reference to $it if it's elided
Parses a column path adding in the preceding reference to $it if it ' s elided
pub fn parse_full_column_path(
    lite_arg: &Spanned<String>,
    registry: &dyn SignatureRegistry,
) -> (SpannedExpression, Option<ParseError>) {
    let mut delimiter = '.';
    let mut inside_delimiter = false;
    let mut output = vec![];
    let mut current_part = String::new();
    let mut start_index = 0;
    let mut last_index = 0;
    let mut error = None;
    let mut head = None;
    for (idx, c) in lite_arg.item.char_indices() {
        last_index = idx;
        if inside_delimiter {
            if c == delimiter {
                inside_delimiter = false;
            }
        } else if c == '(' {
            inside_delimiter = true;
            delimiter = ')';
        } else if c == '\'' || c == '"' {
            inside_delimiter = true;
            delimiter = c;
        } else if c == '.' {
            let part_span = Span::new(
                lite_arg.span.start() + start_index,
                lite_arg.span.start() + idx,
            );
            if head.is_none() && current_part.starts_with("$(") && current_part.ends_with(')') {
                let (invoc, err) =
                    parse_invocation(&current_part.clone().spanned(part_span), registry);
                if error.is_none() {
                    error = err;
                }
                head = Some(invoc.expr);
            } else if head.is_none() && current_part.starts_with('$') {
                // We have the variable head
                head = Some(Expression::variable(current_part.clone(), part_span))
            } else if let Ok(row_number) = current_part.parse::<u64>() {
                output.push(
                    UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
                );
            } else {
                let current_part = trim_quotes(&current_part);
                output.push(
                    UnspannedPathMember::String(current_part.clone()).into_path_member(part_span),
                );
            }
            current_part.clear();
            // Note: I believe this is safe because of the delimiter we're using, but if we get fancy with
            // unicode we'll need to change this
            start_index = idx + '.'.len_utf8();
            continue;
        }
        current_part.push(c);
    }
    if !current_part.is_empty() {
        let part_span = Span::new(
            lite_arg.span.start() + start_index,
            lite_arg.span.start() + last_index + 1,
        );
        if head.is_none() {
            if current_part.starts_with("$(") && current_part.ends_with(')') {
                let (invoc, err) = parse_invocation(&current_part.spanned(part_span), registry);
                if error.is_none() {
                    error = err;
                }
                head = Some(invoc.expr);
            } else if current_part.starts_with('$') {
                head = Some(Expression::variable(current_part, lite_arg.span));
            } else if let Ok(row_number) = current_part.parse::<u64>() {
                output.push(
                    UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
                );
            } else {
                let current_part = trim_quotes(&current_part);
                output.push(UnspannedPathMember::String(current_part).into_path_member(part_span));
            }
        } else if let Ok(row_number) = current_part.parse::<u64>() {
            output.push(
                UnspannedPathMember::Int(BigInt::from(row_number)).into_path_member(part_span),
            );
        } else {
            let current_part = trim_quotes(&current_part);
            output.push(UnspannedPathMember::String(current_part).into_path_member(part_span));
        }
    }
    if let Some(head) = head {
        (
            SpannedExpression::new(
                Expression::path(SpannedExpression::new(head, lite_arg.span), output),
                lite_arg.span,
            ),
            error,
        )
    } else {
        (
            SpannedExpression::new(
                Expression::path(
                    SpannedExpression::new(
                        Expression::variable("$it".into(), lite_arg.span),
                        lite_arg.span,
                    ),
                    output,
                ),
                lite_arg.span,
            ),
            error,
        )
    }
}
pub fn parse_full_column_path ( lite_arg : & Spanned < String > , registry : & dyn SignatureRegistry , ) -> ( SpannedExpression , Option < ParseError > ) { let mut delimiter = '.' ; let mut inside_delimiter = false ; let mut output = vec ! [ ] ; let mut current_part = String :: new ( ) ; let mut start_index = 0 ; let mut last_index = 0 ; let mut error = None ; let mut head = None ; for ( idx , c ) in lite_arg . item . char_indices ( ) { last_index = idx ; if inside_delimiter { if c == delimiter { inside_delimiter = false ; } } else if c == '(' { inside_delimiter = true ; delimiter = ')' ; } else if c == '\'' || c == '"' { inside_delimiter = true ; delimiter = c ; } else if c == '.' { let part_span = Span :: new ( lite_arg . span . start ( ) + start_index , lite_arg . span . start ( ) + idx , ) ; if head . is_none ( ) && current_part . starts_with ( " " ) && current_part . ends_with ( ')' ) { let ( invoc , err ) = parse_invocation ( & current_part . clone ( ) . spanned ( part_span ) , registry ) ; if error . is_none ( ) { error = err ; } head = Some ( invoc . expr ) ; } else if head . is_none ( ) && current_part . starts_with ( '$' ) { // We have the variable head head = Some ( Expression :: variable ( current_part . clone ( ) , part_span ) ) } else if let Ok ( row_number ) = current_part . parse :: < u64 > ( ) { output . push ( UnspannedPathMember :: Int ( BigInt :: from ( row_number ) ) . into_path_member ( part_span ) , ) ; } else { let current_part = trim_quotes ( & current_part ) ; output . push ( UnspannedPathMember :: String ( current_part . clone ( ) ) . into_path_member ( part_span ) , ) ; } current_part . clear ( ) ; // Note: I believe this is safe because of the delimiter we're using, but if we get fancy with // unicode we'll need to change this start_index = idx + '.' . len_utf8 ( ) ; continue ; } current_part . push ( c ) ; } if ! current_part . is_empty ( ) { let part_span = Span :: new ( lite_arg . span . start ( ) + start_index , lite_arg . span . start ( ) + last_index + 1 , ) ; if head . is_none ( ) { if current_part . starts_with ( " " ) && current_part . ends_with ( ')' ) { let ( invoc , err ) = parse_invocation ( & current_part . spanned ( part_span ) , registry ) ; if error . is_none ( ) { error = err ; } head = Some ( invoc . expr ) ; } else if current_part . starts_with ( '$' ) { head = Some ( Expression :: variable ( current_part , lite_arg . span ) ) ; } else if let Ok ( row_number ) = current_part . parse :: < u64 > ( ) { output . push ( UnspannedPathMember :: Int ( BigInt :: from ( row_number ) ) . into_path_member ( part_span ) , ) ; } else { let current_part = trim_quotes ( & current_part ) ; output . push ( UnspannedPathMember :: String ( current_part ) . into_path_member ( part_span ) ) ; } } else if let Ok ( row_number ) = current_part . parse :: < u64 > ( ) { output . push ( UnspannedPathMember :: Int ( BigInt :: from ( row_number ) ) . into_path_member ( part_span ) , ) ; } else { let current_part = trim_quotes ( & current_part ) ; output . push ( UnspannedPathMember :: String ( current_part ) . into_path_member ( part_span ) ) ; } } if let Some ( head ) = head { ( SpannedExpression :: new ( Expression :: path ( SpannedExpression :: new ( head , lite_arg . span ) , output ) , lite_arg . span , ) , error , ) } else { ( SpannedExpression :: new ( Expression :: path ( SpannedExpression :: new ( Expression :: variable ( " " . into ( ) , lite_arg . span ) , lite_arg . span , ) , output , ) , lite_arg . span , ) , error , ) } }
Parses a column path, adding in the preceding reference to $it if it's elided
Parses a column path adding in the preceding reference to $it if it ' s elided
lite_arg
&Spanned<String>
registry
&dyn SignatureRegistry
lite_arg
&Spanned<String>
registry
&dyn SignatureRegistry