@@ -558,7 +558,7 @@ where
558
558
context. contribute_arg ( Argument :: Object ( Object :: Buffer ( buffer) . wrap ( ) ) ) ;
559
559
context. retire_op ( op) ;
560
560
}
561
- Opcode :: Package | Opcode :: VarPackage => {
561
+ Opcode :: Package => {
562
562
let mut elements = Vec :: with_capacity ( op. expected_arguments ) ;
563
563
for arg in & op. arguments {
564
564
let Argument :: Object ( object) = arg else { panic ! ( ) } ;
@@ -582,6 +582,27 @@ where
582
582
context. contribute_arg ( Argument :: Object ( Object :: Package ( elements) . wrap ( ) ) ) ;
583
583
context. retire_op ( op) ;
584
584
}
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
+ }
585
606
Opcode :: If => {
586
607
let [
587
608
Argument :: TrackedPc ( start_pc) ,
@@ -918,28 +939,9 @@ where
918
939
assert ! ( !context. block_stack. is_empty( ) ) ;
919
940
920
941
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
922
943
{
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 ( ) ;
943
945
for _ in 0 ..num_elements_left {
944
946
package_op. arguments . push ( Argument :: Object ( Object :: Uninitialized . wrap ( ) ) ) ;
945
947
}
@@ -949,6 +951,33 @@ where
949
951
// package ops for rationale here.
950
952
continue ;
951
953
}
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
+ }
952
981
BlockKind :: IfThenBranch => {
953
982
context. current_block = context. block_stack . pop ( ) . unwrap ( ) ;
954
983
@@ -1087,7 +1116,7 @@ where
1087
1116
* be in the package later.
1088
1117
*/
1089
1118
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) ;
1091
1120
}
1092
1121
Opcode :: Method => {
1093
1122
let start_pc = context. current_block . pc ;
@@ -1307,48 +1336,75 @@ where
1307
1336
* to by a string. This is not well defined by the specification, but matches
1308
1337
* expected behaviour of other interpreters, and is most useful for downstream
1309
1338
* 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.
1310
1342
*/
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
+ }
1316
1356
} 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) ?,
1330
1383
}
1331
- Err ( other) => Err ( other) ?,
1332
1384
}
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 ( ) ) ) ;
1349
1399
}
1400
+ Err ( other) => Err ( other) ?,
1350
1401
}
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 ( ) ) ) ;
1352
1408
}
1353
1409
}
1354
1410
}
@@ -2476,6 +2532,7 @@ pub enum BlockKind {
2476
2532
old_scope : AmlName ,
2477
2533
} ,
2478
2534
Package ,
2535
+ VarPackage ,
2479
2536
/// Used for executing the then-branch of an `DefIfElse`. After finishing, it will check for
2480
2537
/// and skip over an else-branch, if present.
2481
2538
IfThenBranch ,
0 commit comments