Skip to content

Commit 72fa1c0

Browse files
committed
fix: Correct multi-word parameter parsing in CLI
- Remove rejoin_broken_quoted_args workaround that converted argv to string - Switch from parse_single_instruction to parse_from_argv to preserve token boundaries - Add comprehensive bug analysis and root cause documentation in task/ - Add reproduction tests for CLI and parser multi-word parameter handling - Bump version to 0.32.0 to reflect the parser API usage fix
1 parent e23f4cf commit 72fa1c0

15 files changed

+4716
-58
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ path = "module/core/unilang_parser"
121121
default-features = false
122122

123123
[workspace.dependencies.unilang]
124-
version = "~0.31.0"
124+
version = "~0.32.0"
125125
path = "module/core/unilang"
126126
default-features = false
127127

module/core/unilang/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "unilang"
3-
version = "0.31.0"
3+
version = "0.32.0"
44
edition = "2021"
55
rust-version = "1.70"
66
authors = [

module/core/unilang/src/bin/unilang_cli.rs

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,6 @@ use unilang::semantic::SemanticAnalyzer;
2323
use unilang::types::Value;
2424
use unilang_parser::{ Parser, UnilangParserOptions };
2525

26-
/// Rejoins command line arguments that were incorrectly split by the shell
27-
/// when they contain quoted multi-word values.
28-
///
29-
/// For example, if the shell splits `query::"llm rust"` into `["query::\"llm", "rust\""]`,
30-
/// this function will rejoin them back to `query::"llm rust"`.
31-
fn rejoin_broken_quoted_args( args: &[ String ] ) -> String
32-
{
33-
let mut result = Vec::new();
34-
let mut i = 0;
35-
36-
while i < args.len()
37-
{
38-
let current_arg = &args[ i ];
39-
40-
// Check if this argument has an unmatched opening quote
41-
if current_arg.contains( "::\"" ) && !current_arg.ends_with( '"' )
42-
{
43-
// This argument starts a quoted value, look for the closing quote
44-
let mut combined_arg = current_arg.clone();
45-
i += 1;
46-
47-
// Keep adding arguments until we find the closing quote
48-
while i < args.len()
49-
{
50-
combined_arg.push( ' ' );
51-
combined_arg.push_str( &args[ i ] );
52-
53-
if args[ i ].ends_with( '"' )
54-
{
55-
// Found the closing quote
56-
break;
57-
}
58-
i += 1;
59-
}
60-
61-
result.push( combined_arg );
62-
}
63-
else
64-
{
65-
// Regular argument, add as-is
66-
result.push( current_arg.clone() );
67-
}
68-
69-
i += 1;
70-
}
71-
72-
result.join( " " )
73-
}
74-
7526
fn main()
7627
{
7728
if let Err( err ) = run()
@@ -593,16 +544,15 @@ fn run() -> Result< (), unilang::error::Error >
593544
return Ok( () );
594545
}
595546

596-
// Fix for quoted multi-word values: rejoin arguments that were incorrectly split by the shell
597-
let command_input_str = rejoin_broken_quoted_args( &processed_args );
598-
599-
// Debug: print the processed arguments and the rejoined command
547+
// Parse command using argv-aware parser to properly handle multi-word parameter values.
548+
// The shell removes quotes from arguments like query::"llm rust", resulting in
549+
// argv = ["query::llm rust"] (one token). Using parse_from_argv() preserves these
550+
// token boundaries, while parse_single_instruction() would re-tokenize on spaces.
600551
if verbosity > 1
601552
{
602-
eprintln!( "DEBUG: Processed arguments: {processed_args:?}" );
603-
eprintln!( "DEBUG: Rejoined command string: {command_input_str:?}" );
553+
eprintln!( "DEBUG: Processing argv: {processed_args:?}" );
604554
}
605-
let instruction = parser.parse_single_instruction( &command_input_str )?;
555+
let instruction = parser.parse_from_argv( &processed_args )?;
606556
let instructions = &[ instruction ][ .. ];
607557

608558
// 4. Semantic Analysis

0 commit comments

Comments
 (0)