@@ -517,7 +517,7 @@ fn parse_shell_var(pair: Pair<Rule>) -> Result<Sequence> {
517517 let value = inner
518518 . next ( )
519519 . ok_or_else ( || anyhow:: anyhow!( "Expected variable value" ) ) ?;
520- let value = parse_word ( value) ?;
520+ let value = parse_assignment_value ( value) ?;
521521 Ok ( Sequence :: ShellVar ( EnvVar { name, value } ) )
522522}
523523
@@ -1046,6 +1046,372 @@ mod test {
10461046
10471047 assert ! ( parse( "echo \" foo\" > out.txt" ) . is_ok( ) ) ;
10481048 }
1049+ #[ test]
1050+ fn test_sequential_list ( ) {
1051+ let parse_and_create = |input : & str | -> Result < SequentialList > {
1052+ let pairs = ShellParser :: parse ( Rule :: complete_command, input)
1053+ . map_err ( |e| anyhow:: Error :: msg ( e. to_string ( ) ) ) ?
1054+ . next ( )
1055+ . unwrap ( ) ;
1056+ // println!("pairs: {:?}", pairs);
1057+ parse_complete_command ( pairs)
1058+ } ;
1059+
1060+ // Test case 1
1061+ let input = concat ! (
1062+ "Name=Value OtherVar=Other command arg1 || command2 arg12 arg13 ; " ,
1063+ "command3 && command4 & command5 ; export ENV6=5 ; " ,
1064+ "ENV7=other && command8 || command9 ; " ,
1065+ "cmd10 && (cmd11 || cmd12)"
1066+ ) ;
1067+ let result = parse_and_create ( input) . unwrap ( ) ;
1068+ let expected = SequentialList {
1069+ items : vec ! [
1070+ SequentialListItem {
1071+ is_async: false ,
1072+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1073+ current: SimpleCommand {
1074+ env_vars: vec![
1075+ EnvVar :: new( "Name" . to_string( ) , Word :: new_word( "Value" ) ) ,
1076+ EnvVar :: new( "OtherVar" . to_string( ) , Word :: new_word( "Other" ) ) ,
1077+ ] ,
1078+ args: vec![ Word :: new_word( "command" ) , Word :: new_word( "arg1" ) ] ,
1079+ }
1080+ . into( ) ,
1081+ op: BooleanListOperator :: Or ,
1082+ next: SimpleCommand {
1083+ env_vars: vec![ ] ,
1084+ args: vec![
1085+ Word :: new_word( "command2" ) ,
1086+ Word :: new_word( "arg12" ) ,
1087+ Word :: new_word( "arg13" ) ,
1088+ ] ,
1089+ }
1090+ . into( ) ,
1091+ } ) ) ,
1092+ } ,
1093+ SequentialListItem {
1094+ is_async: true ,
1095+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1096+ current: SimpleCommand {
1097+ env_vars: vec![ ] ,
1098+ args: vec![ Word :: new_word( "command3" ) ] ,
1099+ }
1100+ . into( ) ,
1101+ op: BooleanListOperator :: And ,
1102+ next: SimpleCommand {
1103+ env_vars: vec![ ] ,
1104+ args: vec![ Word :: new_word( "command4" ) ] ,
1105+ }
1106+ . into( ) ,
1107+ } ) ) ,
1108+ } ,
1109+ SequentialListItem {
1110+ is_async: false ,
1111+ sequence: SimpleCommand {
1112+ env_vars: vec![ ] ,
1113+ args: vec![ Word :: new_word( "command5" ) ] ,
1114+ }
1115+ . into( ) ,
1116+ } ,
1117+ SequentialListItem {
1118+ is_async: false ,
1119+ sequence: SimpleCommand {
1120+ env_vars: vec![ ] ,
1121+ args: vec![ Word :: new_word( "export" ) , Word :: new_word( "ENV6=5" ) ] ,
1122+ }
1123+ . into( ) ,
1124+ } ,
1125+ SequentialListItem {
1126+ is_async: false ,
1127+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1128+ current: Sequence :: ShellVar ( EnvVar :: new(
1129+ "ENV7" . to_string( ) ,
1130+ Word :: new_word( "other" ) ,
1131+ ) ) ,
1132+ op: BooleanListOperator :: And ,
1133+ next: Sequence :: BooleanList ( Box :: new( BooleanList {
1134+ current: SimpleCommand {
1135+ env_vars: vec![ ] ,
1136+ args: vec![ Word :: new_word( "command8" ) ] ,
1137+ }
1138+ . into( ) ,
1139+ op: BooleanListOperator :: Or ,
1140+ next: SimpleCommand {
1141+ env_vars: vec![ ] ,
1142+ args: vec![ Word :: new_word( "command9" ) ] ,
1143+ }
1144+ . into( ) ,
1145+ } ) ) ,
1146+ } ) ) ,
1147+ } ,
1148+ SequentialListItem {
1149+ is_async: false ,
1150+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1151+ current: SimpleCommand {
1152+ env_vars: vec![ ] ,
1153+ args: vec![ Word :: new_word( "cmd10" ) ] ,
1154+ }
1155+ . into( ) ,
1156+ op: BooleanListOperator :: And ,
1157+ next: Command {
1158+ inner: CommandInner :: Subshell ( Box :: new( SequentialList {
1159+ items: vec![ SequentialListItem {
1160+ is_async: false ,
1161+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1162+ current: SimpleCommand {
1163+ env_vars: vec![ ] ,
1164+ args: vec![ Word :: new_word( "cmd11" ) ] ,
1165+ }
1166+ . into( ) ,
1167+ op: BooleanListOperator :: Or ,
1168+ next: SimpleCommand {
1169+ env_vars: vec![ ] ,
1170+ args: vec![ Word :: new_word( "cmd12" ) ] ,
1171+ }
1172+ . into( ) ,
1173+ } ) ) ,
1174+ } ] ,
1175+ } ) ) ,
1176+ redirect: None ,
1177+ }
1178+ . into( ) ,
1179+ } ) ) ,
1180+ } ,
1181+ ] ,
1182+ } ;
1183+ assert_eq ! ( result, expected) ;
1184+
1185+ // Test case 2
1186+ let input = "command1 ; command2 ; A='b' command3" ;
1187+ let result = parse_and_create ( input) . unwrap ( ) ;
1188+ let expected = SequentialList {
1189+ items : vec ! [
1190+ SequentialListItem {
1191+ is_async: false ,
1192+ sequence: SimpleCommand {
1193+ env_vars: vec![ ] ,
1194+ args: vec![ Word :: new_word( "command1" ) ] ,
1195+ }
1196+ . into( ) ,
1197+ } ,
1198+ SequentialListItem {
1199+ is_async: false ,
1200+ sequence: SimpleCommand {
1201+ env_vars: vec![ ] ,
1202+ args: vec![ Word :: new_word( "command2" ) ] ,
1203+ }
1204+ . into( ) ,
1205+ } ,
1206+ SequentialListItem {
1207+ is_async: false ,
1208+ sequence: SimpleCommand {
1209+ env_vars: vec![ EnvVar :: new( "A" . to_string( ) , Word :: new_string( "b" ) ) ] ,
1210+ args: vec![ Word :: new_word( "command3" ) ] ,
1211+ }
1212+ . into( ) ,
1213+ } ,
1214+ ] ,
1215+ } ;
1216+ assert_eq ! ( result, expected) ;
1217+
1218+ // Test case 3
1219+ let input = "test &&" ;
1220+ assert ! ( parse_and_create( input) . is_err( ) ) ;
1221+
1222+ // Test case 4
1223+ let input = "command &" ;
1224+ let result = parse_and_create ( input) . unwrap ( ) ;
1225+ let expected = SequentialList {
1226+ items : vec ! [ SequentialListItem {
1227+ is_async: true ,
1228+ sequence: SimpleCommand {
1229+ env_vars: vec![ ] ,
1230+ args: vec![ Word :: new_word( "command" ) ] ,
1231+ }
1232+ . into( ) ,
1233+ } ] ,
1234+ } ;
1235+ assert_eq ! ( result, expected) ;
1236+
1237+ // Test case 5
1238+ let input = "test | other" ;
1239+ let result = parse_and_create ( input) . unwrap ( ) ;
1240+ let expected = SequentialList {
1241+ items : vec ! [ SequentialListItem {
1242+ is_async: false ,
1243+ sequence: PipeSequence {
1244+ current: SimpleCommand {
1245+ env_vars: vec![ ] ,
1246+ args: vec![ Word :: new_word( "test" ) ] ,
1247+ }
1248+ . into( ) ,
1249+ op: PipeSequenceOperator :: Stdout ,
1250+ next: SimpleCommand {
1251+ env_vars: vec![ ] ,
1252+ args: vec![ Word :: new_word( "other" ) ] ,
1253+ }
1254+ . into( ) ,
1255+ }
1256+ . into( ) ,
1257+ } ] ,
1258+ } ;
1259+ assert_eq ! ( result, expected) ;
1260+
1261+ // Test case 6
1262+ let input = "test |& other" ;
1263+ let result = parse_and_create ( input) . unwrap ( ) ;
1264+ let expected = SequentialList {
1265+ items : vec ! [ SequentialListItem {
1266+ is_async: false ,
1267+ sequence: PipeSequence {
1268+ current: SimpleCommand {
1269+ env_vars: vec![ ] ,
1270+ args: vec![ Word :: new_word( "test" ) ] ,
1271+ }
1272+ . into( ) ,
1273+ op: PipeSequenceOperator :: StdoutStderr ,
1274+ next: SimpleCommand {
1275+ env_vars: vec![ ] ,
1276+ args: vec![ Word :: new_word( "other" ) ] ,
1277+ }
1278+ . into( ) ,
1279+ }
1280+ . into( ) ,
1281+ } ] ,
1282+ } ;
1283+ assert_eq ! ( result, expected) ;
1284+
1285+ // Test case 8
1286+ let input = "echo $MY_ENV;" ;
1287+ let result = parse_and_create ( input) . unwrap ( ) ;
1288+ let expected = SequentialList {
1289+ items : vec ! [ SequentialListItem {
1290+ is_async: false ,
1291+ sequence: SimpleCommand {
1292+ env_vars: vec![ ] ,
1293+ args: vec![
1294+ Word :: new_word( "echo" ) ,
1295+ Word ( vec![ WordPart :: Variable ( "MY_ENV" . to_string( ) ) ] ) ,
1296+ ] ,
1297+ }
1298+ . into( ) ,
1299+ } ] ,
1300+ } ;
1301+ assert_eq ! ( result, expected) ;
1302+
1303+ // Test case 9
1304+ let input = "! cmd1 | cmd2 && cmd3" ;
1305+ let result = parse_and_create ( input) . unwrap ( ) ;
1306+ let expected = SequentialList {
1307+ items : vec ! [ SequentialListItem {
1308+ is_async: false ,
1309+ sequence: Sequence :: BooleanList ( Box :: new( BooleanList {
1310+ current: Pipeline {
1311+ negated: true ,
1312+ inner: PipeSequence {
1313+ current: SimpleCommand {
1314+ args: vec![ Word :: new_word( "cmd1" ) ] ,
1315+ env_vars: vec![ ] ,
1316+ }
1317+ . into( ) ,
1318+ op: PipeSequenceOperator :: Stdout ,
1319+ next: SimpleCommand {
1320+ args: vec![ Word :: new_word( "cmd2" ) ] ,
1321+ env_vars: vec![ ] ,
1322+ }
1323+ . into( ) ,
1324+ }
1325+ . into( ) ,
1326+ }
1327+ . into( ) ,
1328+ op: BooleanListOperator :: And ,
1329+ next: SimpleCommand {
1330+ args: vec![ Word :: new_word( "cmd3" ) ] ,
1331+ env_vars: vec![ ] ,
1332+ }
1333+ . into( ) ,
1334+ } ) ) ,
1335+ } ] ,
1336+ } ;
1337+ assert_eq ! ( result, expected) ;
1338+ }
1339+
1340+ #[ test]
1341+ fn test_env_var ( ) {
1342+ let parse_and_create = |input : & str | -> Result < EnvVar , anyhow:: Error > {
1343+ let pairs = ShellParser :: parse ( Rule :: ASSIGNMENT_WORD , input)
1344+ . map_err ( |e| anyhow:: anyhow!( e. to_string( ) ) ) ?
1345+ . next ( )
1346+ . unwrap ( ) ;
1347+ parse_env_var ( pairs)
1348+ } ;
1349+
1350+ assert_eq ! (
1351+ parse_and_create( "Name=Value" ) . unwrap( ) ,
1352+ EnvVar {
1353+ name: "Name" . to_string( ) ,
1354+ value: Word :: new_word( "Value" ) ,
1355+ }
1356+ ) ;
1357+
1358+ assert_eq ! (
1359+ parse_and_create( "Name='quoted value'" ) . unwrap( ) ,
1360+ EnvVar {
1361+ name: "Name" . to_string( ) ,
1362+ value: Word :: new_string( "quoted value" ) ,
1363+ }
1364+ ) ;
1365+
1366+ assert_eq ! (
1367+ parse_and_create( "Name=\" double quoted value\" " ) . unwrap( ) ,
1368+ EnvVar {
1369+ name: "Name" . to_string( ) ,
1370+ value: Word :: new_string( "double quoted value" ) ,
1371+ }
1372+ ) ;
1373+
1374+ assert_eq ! (
1375+ parse_and_create( "Name=" ) . unwrap( ) ,
1376+ EnvVar {
1377+ name: "Name" . to_string( ) ,
1378+ value: Word ( vec![ ] ) ,
1379+ }
1380+ ) ;
1381+
1382+ assert_eq ! (
1383+ parse_and_create( "Name=$(test)" ) . unwrap( ) ,
1384+ EnvVar {
1385+ name: "Name" . to_string( ) ,
1386+ value: Word ( vec![ WordPart :: Command ( SequentialList {
1387+ items: vec![ SequentialListItem {
1388+ is_async: false ,
1389+ sequence: SimpleCommand {
1390+ env_vars: vec![ ] ,
1391+ args: vec![ Word :: new_word( "test" ) ] ,
1392+ }
1393+ . into( ) ,
1394+ } ] ,
1395+ } ) ] ) ,
1396+ }
1397+ ) ;
1398+
1399+ assert_eq ! (
1400+ parse_and_create( "Name=$(OTHER=5)" ) . unwrap( ) ,
1401+ EnvVar {
1402+ name: "Name" . to_string( ) ,
1403+ value: Word ( vec![ WordPart :: Command ( SequentialList {
1404+ items: vec![ SequentialListItem {
1405+ is_async: false ,
1406+ sequence: Sequence :: ShellVar ( EnvVar {
1407+ name: "OTHER" . to_string( ) ,
1408+ value: Word :: new_word( "5" ) ,
1409+ } ) ,
1410+ } ] ,
1411+ } ) ] ) ,
1412+ }
1413+ ) ;
1414+ }
10491415
10501416 #[ cfg( feature = "serialization" ) ]
10511417 #[ test]
0 commit comments