| 1043 | } |
| 1044 | |
| 1045 | pub fn split_localplus<S: Clone>( |
| 1046 | names: &[S], |
| 1047 | kinds: &[u8], |
| 1048 | arg_count: u32, |
| 1049 | kwonlyarg_count: u32, |
| 1050 | flags: CodeFlags, |
| 1051 | ) -> Result<LocalsPlusResult<S>> { |
| 1052 | if names.len() != kinds.len() { |
| 1053 | return Err(MarshalError::InvalidBytecode); |
| 1054 | } |
| 1055 | |
| 1056 | let mut varnames = Vec::new(); |
| 1057 | let mut cellvars = Vec::new(); |
| 1058 | let mut freevars = Vec::new(); |
| 1059 | |
| 1060 | // First pass: collect varnames (LOCAL entries) and freevars |
| 1061 | for (name, &kind) in names.iter().zip(kinds.iter()) { |
| 1062 | if kind & CO_FAST_LOCAL != 0 { |
| 1063 | varnames.push(name.clone()); |
| 1064 | } |
| 1065 | if kind & CO_FAST_FREE != 0 { |
| 1066 | freevars.push(name.clone()); |
| 1067 | } |
| 1068 | } |
| 1069 | |
| 1070 | // Second pass: collect cellvars in localsplusnames order. |
| 1071 | // CELL-only vars come from non-LOCAL CELL entries. |
| 1072 | // LOCAL|CELL vars are also added to cellvars. |
| 1073 | // This preserves the original ordering from localsplusnames. |
| 1074 | let mut arg_cell_positions = Vec::new(); // (cell_idx, localplus_idx) |
| 1075 | for (i, (name, &kind)) in names.iter().zip(kinds.iter()).enumerate() { |
| 1076 | let is_local = kind & CO_FAST_LOCAL != 0; |
| 1077 | let is_cell = kind & CO_FAST_CELL != 0; |
| 1078 | if is_cell { |
| 1079 | let cell_idx = cellvars.len(); |
| 1080 | cellvars.push(name.clone()); |
| 1081 | if is_local { |
| 1082 | arg_cell_positions.push((cell_idx, i)); |
| 1083 | } |
| 1084 | } |
| 1085 | } |
| 1086 | |
| 1087 | let total_args = { |
| 1088 | let mut t = arg_count + kwonlyarg_count; |
| 1089 | if flags.contains(CodeFlags::VARARGS) { |
| 1090 | t += 1; |
| 1091 | } |
| 1092 | if flags.contains(CodeFlags::VARKEYWORDS) { |
| 1093 | t += 1; |
| 1094 | } |
| 1095 | t |
| 1096 | }; |
| 1097 | |
| 1098 | let cell2arg = if !cellvars.is_empty() { |
| 1099 | let mut mapping = alloc::vec![-1i32; cellvars.len()]; |
| 1100 | for &(cell_idx, localplus_idx) in &arg_cell_positions { |
| 1101 | if (localplus_idx as u32) < total_args { |
| 1102 | mapping[cell_idx] = localplus_idx as i32; |