@@ -558,7 +558,7 @@ where
558558 context. contribute_arg ( Argument :: Object ( Object :: Buffer ( buffer) . wrap ( ) ) ) ;
559559 context. retire_op ( op) ;
560560 }
561- Opcode :: Package | Opcode :: VarPackage => {
561+ Opcode :: Package => {
562562 let mut elements = Vec :: with_capacity ( op. expected_arguments ) ;
563563 for arg in & op. arguments {
564564 let Argument :: Object ( object) = arg else { panic ! ( ) } ;
@@ -582,6 +582,27 @@ where
582582 context. contribute_arg ( Argument :: Object ( Object :: Package ( elements) . wrap ( ) ) ) ;
583583 context. retire_op ( op) ;
584584 }
585+ Opcode :: VarPackage => {
586+ let Argument :: Object ( total_elements) = & op. arguments [ 0 ] else { panic ! ( ) } ;
587+ let total_elements =
588+ total_elements. clone ( ) . unwrap_transparent_reference ( ) . as_integer ( ) ? as usize ;
589+
590+ let mut elements = Vec :: with_capacity ( total_elements) ;
591+ for arg in & op. arguments [ 1 ..] {
592+ let Argument :: Object ( object) = arg else { panic ! ( ) } ;
593+ elements. push ( object. clone ( ) ) ;
594+ }
595+
596+ /*
597+ * As above, we always remove the block here after the in-flight op has
598+ * been retired.
599+ */
600+ assert_eq ! ( context. current_block. kind, BlockKind :: VarPackage ) ;
601+ assert_eq ! ( context. peek( ) , Err ( AmlError :: RunOutOfStream ) ) ;
602+ context. current_block = context. block_stack . pop ( ) . unwrap ( ) ;
603+ context. contribute_arg ( Argument :: Object ( Object :: Package ( elements) . wrap ( ) ) ) ;
604+ context. retire_op ( op) ;
605+ }
585606 Opcode :: If => {
586607 let [
587608 Argument :: TrackedPc ( start_pc) ,
@@ -918,28 +939,9 @@ where
918939 assert ! ( !context. block_stack. is_empty( ) ) ;
919940
920941 if let Some ( package_op) = context. in_flight . last_mut ( )
921- && ( package_op. op == Opcode :: Package || package_op . op == Opcode :: VarPackage )
942+ && package_op. op == Opcode :: Package
922943 {
923- let num_elements_left = match package_op. op {
924- Opcode :: Package => package_op. expected_arguments - package_op. arguments . len ( ) ,
925- Opcode :: VarPackage => {
926- let Argument :: Object ( total_elements) = & package_op. arguments [ 0 ] else {
927- panic ! ( )
928- } ;
929- let total_elements =
930- total_elements. clone ( ) . unwrap_transparent_reference ( ) . as_integer ( ) ?
931- as usize ;
932-
933- // Update the expected number of arguments to terminate the in-flight op
934- package_op. expected_arguments = total_elements;
935-
936- total_elements - package_op. arguments . len ( )
937- }
938- _ => panic ! (
939- "Current in-flight op is not a `Package` or `VarPackage` when finished parsing package block"
940- ) ,
941- } ;
942-
944+ let num_elements_left = package_op. expected_arguments - package_op. arguments . len ( ) ;
943945 for _ in 0 ..num_elements_left {
944946 package_op. arguments . push ( Argument :: Object ( Object :: Uninitialized . wrap ( ) ) ) ;
945947 }
@@ -949,6 +951,33 @@ where
949951 // package ops for rationale here.
950952 continue ;
951953 }
954+ BlockKind :: VarPackage => {
955+ assert ! ( !context. block_stack. is_empty( ) ) ;
956+
957+ if let Some ( package_op) = context. in_flight . last_mut ( )
958+ && package_op. op == Opcode :: VarPackage
959+ {
960+ let num_elements_left = {
961+ let Argument :: Object ( total_elements) = & package_op. arguments [ 0 ] else {
962+ panic ! ( )
963+ } ;
964+ let total_elements =
965+ total_elements. clone ( ) . unwrap_transparent_reference ( ) . as_integer ( ) ?
966+ as usize ;
967+
968+ // Update the expected number of arguments to terminate the in-flight op
969+ package_op. expected_arguments = package_op. arguments . len ( ) ;
970+ total_elements - ( package_op. arguments . len ( ) - 1 )
971+ } ;
972+
973+ for _ in 0 ..num_elements_left {
974+ package_op. arguments . push ( Argument :: Object ( Object :: Uninitialized . wrap ( ) ) ) ;
975+ }
976+ }
977+
978+ // As above, leave the package's block.
979+ continue ;
980+ }
952981 BlockKind :: IfThenBranch => {
953982 context. current_block = context. block_stack . pop ( ) . unwrap ( ) ;
954983
@@ -1087,7 +1116,7 @@ where
10871116 * be in the package later.
10881117 */
10891118 context. start_in_flight_op ( OpInFlight :: new ( Opcode :: VarPackage , usize:: MAX ) ) ;
1090- context. start_new_block ( BlockKind :: Package , remaining_length) ;
1119+ context. start_new_block ( BlockKind :: VarPackage , remaining_length) ;
10911120 }
10921121 Opcode :: Method => {
10931122 let start_pc = context. current_block . pc ;
@@ -1307,48 +1336,75 @@ where
13071336 * to by a string. This is not well defined by the specification, but matches
13081337 * expected behaviour of other interpreters, and is most useful for downstream
13091338 * users.
1339+ * - In variable-length package definitions, the first 'element' is the
1340+ * length of the package, and should be resolved to an object. The
1341+ * remaining elements should be treated the same as in a package definition.
13101342 */
1311- if context. current_block . kind == BlockKind :: Package {
1312- context
1313- . last_op ( ) ?
1314- . arguments
1315- . push ( Argument :: Object ( Object :: String ( name. to_string ( ) ) . wrap ( ) ) ) ;
1343+ enum ResolveBehaviour {
1344+ ResolveToObject ,
1345+ ResolveIfExists ,
1346+ PackageElement ,
1347+ }
1348+ let behaviour = if context. current_block . kind == BlockKind :: Package {
1349+ ResolveBehaviour :: PackageElement
1350+ } else if context. current_block . kind == BlockKind :: VarPackage {
1351+ if context. last_op ( ) ?. arguments . len ( ) == 0 {
1352+ ResolveBehaviour :: ResolveToObject
1353+ } else {
1354+ ResolveBehaviour :: PackageElement
1355+ }
13161356 } else if context. in_flight . last ( ) . map ( |op| op. op == Opcode :: CondRefOf ) . unwrap_or ( false ) {
1317- let object = self . namespace . lock ( ) . search ( & name, & context. current_scope ) ;
1318- match object {
1319- Ok ( ( _, object) ) => {
1320- let reference =
1321- Object :: Reference { kind : ReferenceKind :: RefOf , inner : object. clone ( ) } ;
1322- context. last_op ( ) ?. arguments . push ( Argument :: Object ( reference. wrap ( ) ) ) ;
1323- }
1324- Err ( AmlError :: ObjectDoesNotExist ( _) ) => {
1325- let reference = Object :: Reference {
1326- kind : ReferenceKind :: Unresolved ,
1327- inner : Object :: String ( name. to_string ( ) ) . wrap ( ) ,
1328- } ;
1329- context. last_op ( ) ?. arguments . push ( Argument :: Object ( reference. wrap ( ) ) ) ;
1357+ ResolveBehaviour :: ResolveIfExists
1358+ } else {
1359+ ResolveBehaviour :: ResolveToObject
1360+ } ;
1361+
1362+ match behaviour {
1363+ ResolveBehaviour :: ResolveToObject => {
1364+ let object = self . namespace . lock ( ) . search ( & name, & context. current_scope ) ;
1365+ match object {
1366+ Ok ( ( resolved_name, object) ) => {
1367+ if let Object :: Method { flags, .. } | Object :: NativeMethod { flags, .. } =
1368+ * object
1369+ {
1370+ context. start_in_flight_op ( OpInFlight :: new_with (
1371+ Opcode :: InternalMethodCall ,
1372+ vec ! [ Argument :: Object ( object) , Argument :: Namestring ( resolved_name) ] ,
1373+ flags. arg_count ( ) ,
1374+ ) )
1375+ } else if let Object :: FieldUnit ( ref field) = * object {
1376+ let value = self . do_field_read ( field) ?;
1377+ context. last_op ( ) ?. arguments . push ( Argument :: Object ( value) ) ;
1378+ } else {
1379+ context. last_op ( ) ?. arguments . push ( Argument :: Object ( object) ) ;
1380+ }
1381+ }
1382+ Err ( err) => Err ( err) ?,
13301383 }
1331- Err ( other) => Err ( other) ?,
13321384 }
1333- } else {
1334- let object = self . namespace . lock ( ) . search ( & name, & context. current_scope ) ;
1335- match object {
1336- Ok ( ( resolved_name, object) ) => {
1337- if let Object :: Method { flags, .. } | Object :: NativeMethod { flags, .. } = * object
1338- {
1339- context. start_in_flight_op ( OpInFlight :: new_with (
1340- Opcode :: InternalMethodCall ,
1341- vec ! [ Argument :: Object ( object) , Argument :: Namestring ( resolved_name) ] ,
1342- flags. arg_count ( ) ,
1343- ) )
1344- } else if let Object :: FieldUnit ( ref field) = * object {
1345- let value = self . do_field_read ( field) ?;
1346- context. last_op ( ) ?. arguments . push ( Argument :: Object ( value) ) ;
1347- } else {
1348- context. last_op ( ) ?. arguments . push ( Argument :: Object ( object) ) ;
1385+ ResolveBehaviour :: ResolveIfExists => {
1386+ let object = self . namespace . lock ( ) . search ( & name, & context. current_scope ) ;
1387+ match object {
1388+ Ok ( ( _, object) ) => {
1389+ let reference =
1390+ Object :: Reference { kind : ReferenceKind :: RefOf , inner : object. clone ( ) } ;
1391+ context. last_op ( ) ?. arguments . push ( Argument :: Object ( reference. wrap ( ) ) ) ;
1392+ }
1393+ Err ( AmlError :: ObjectDoesNotExist ( _) ) => {
1394+ let reference = Object :: Reference {
1395+ kind : ReferenceKind :: Unresolved ,
1396+ inner : Object :: String ( name. to_string ( ) ) . wrap ( ) ,
1397+ } ;
1398+ context. last_op ( ) ?. arguments . push ( Argument :: Object ( reference. wrap ( ) ) ) ;
13491399 }
1400+ Err ( other) => Err ( other) ?,
13501401 }
1351- Err ( err) => Err ( err) ?,
1402+ }
1403+ ResolveBehaviour :: PackageElement => {
1404+ context
1405+ . last_op ( ) ?
1406+ . arguments
1407+ . push ( Argument :: Object ( Object :: String ( name. to_string ( ) ) . wrap ( ) ) ) ;
13521408 }
13531409 }
13541410 }
@@ -2476,6 +2532,7 @@ pub enum BlockKind {
24762532 old_scope : AmlName ,
24772533 } ,
24782534 Package ,
2535+ VarPackage ,
24792536 /// Used for executing the then-branch of an `DefIfElse`. After finishing, it will check for
24802537 /// and skip over an else-branch, if present.
24812538 IfThenBranch ,
0 commit comments