@@ -527,6 +527,14 @@ impl FormatModule {
527
527
self . define_format_args ( name, vec ! [ ] , format)
528
528
}
529
529
530
+ pub fn define_format_rec (
531
+ & mut self ,
532
+ name : impl Into < String > ,
533
+ f : impl FnOnce ( FormatRef ) -> Format ,
534
+ ) -> FormatRef {
535
+ self . define_format_args_rec ( name, vec ! [ ] , f)
536
+ }
537
+
530
538
pub fn define_format_args (
531
539
& mut self ,
532
540
name : impl Into < String > ,
@@ -549,6 +557,32 @@ impl FormatModule {
549
557
FormatRef ( level)
550
558
}
551
559
560
+ pub fn define_format_args_rec (
561
+ & mut self ,
562
+ name : impl Into < String > ,
563
+ args : Vec < ( String , ValueType ) > ,
564
+ f : impl FnOnce ( FormatRef ) -> Format ,
565
+ ) -> FormatRef {
566
+ let format_ref = FormatRef ( self . names . len ( ) ) ;
567
+ let format = f ( format_ref) ;
568
+ if let Err ( ( ) ) = format. recursion_check ( self , format_ref) {
569
+ panic ! ( "format fails recursion check!" ) ;
570
+ }
571
+ let mut scope = TypeScope :: new ( ) ;
572
+ for ( arg_name, arg_type) in & args {
573
+ scope. push ( arg_name. clone ( ) , arg_type. clone ( ) ) ;
574
+ }
575
+ let format_type = match self . infer_format_type ( & mut scope, & format) {
576
+ Ok ( t) => t,
577
+ Err ( msg) => panic ! ( "{msg}" ) ,
578
+ } ;
579
+ self . names . push ( name. into ( ) ) ;
580
+ self . args . push ( args) ;
581
+ self . formats . push ( format) ;
582
+ self . format_types . push ( format_type) ;
583
+ format_ref
584
+ }
585
+
552
586
fn get_name ( & self , level : usize ) -> & str {
553
587
& self . names [ level]
554
588
}
@@ -1307,6 +1341,93 @@ impl Format {
1307
1341
}
1308
1342
MatchTree :: build ( module, & fs, Rc :: new ( Next :: Empty ) ) . is_none ( )
1309
1343
}
1344
+
1345
+ fn recursion_check ( & self , module : & FormatModule , format_ref : FormatRef ) -> Result < bool , ( ) > {
1346
+ match self {
1347
+ Format :: ItemVar ( level, _arg_exprs) => {
1348
+ if format_ref. get_level ( ) == * level {
1349
+ Err ( ( ) )
1350
+ } else {
1351
+ Ok ( module. get_format ( * level) . is_nullable ( module) )
1352
+ }
1353
+ }
1354
+ Format :: Fail => Ok ( false ) ,
1355
+ Format :: EndOfInput => Ok ( true ) ,
1356
+ Format :: Align ( _n) => Ok ( true ) ,
1357
+ Format :: Byte ( _bs) => Ok ( false ) ,
1358
+ Format :: Union ( branches) | Format :: NondetUnion ( branches) => {
1359
+ let mut nullable = false ;
1360
+ for ( _label, f) in branches {
1361
+ nullable = nullable || f. recursion_check ( module, format_ref) ?;
1362
+ }
1363
+ Ok ( nullable)
1364
+ }
1365
+ Format :: Tuple ( fields) => {
1366
+ for f in fields {
1367
+ if !f. recursion_check ( module, format_ref) ? {
1368
+ return Ok ( false ) ;
1369
+ }
1370
+ }
1371
+ Ok ( true )
1372
+ }
1373
+ Format :: Record ( fields) => {
1374
+ for ( _label, f) in fields {
1375
+ if !f. recursion_check ( module, format_ref) ? {
1376
+ return Ok ( false ) ;
1377
+ }
1378
+ }
1379
+ Ok ( true )
1380
+ }
1381
+ Format :: Repeat ( a) => {
1382
+ a. recursion_check ( module, format_ref) ?;
1383
+ Ok ( true )
1384
+ }
1385
+ Format :: Repeat1 ( a) => {
1386
+ a. recursion_check ( module, format_ref) ?;
1387
+ Ok ( false )
1388
+ }
1389
+ Format :: RepeatCount ( _expr, a)
1390
+ | Format :: RepeatUntilLast ( _expr, a)
1391
+ | Format :: RepeatUntilSeq ( _expr, a) => {
1392
+ a. recursion_check ( module, format_ref) ?;
1393
+ Ok ( true ) // FIXME bit sloppy but okay
1394
+ }
1395
+ Format :: Peek ( a) => {
1396
+ a. recursion_check ( module, format_ref) ?;
1397
+ Ok ( true )
1398
+ }
1399
+ Format :: PeekNot ( a) => {
1400
+ a. recursion_check ( module, format_ref) ?;
1401
+ Ok ( true )
1402
+ }
1403
+ Format :: Slice ( expr, a) => {
1404
+ a. recursion_check ( module, format_ref) ?;
1405
+ Ok ( expr. bounds ( ) . min == 0 )
1406
+ }
1407
+ Format :: Bits ( _a) => Ok ( false ) ,
1408
+ Format :: WithRelativeOffset ( _expr, a) => {
1409
+ a. recursion_check ( module, format_ref) ?; // technically okay if expr > 0
1410
+ Ok ( true )
1411
+ }
1412
+ Format :: Compute ( _expr) => Ok ( true ) ,
1413
+ Format :: Match ( _head, branches) => {
1414
+ let mut nullable = false ;
1415
+ for ( _pattern, f) in branches {
1416
+ nullable = nullable || f. recursion_check ( module, format_ref) ?;
1417
+ }
1418
+ Ok ( nullable)
1419
+ }
1420
+ Format :: MatchVariant ( _head, branches) => {
1421
+ let mut nullable = false ;
1422
+ for ( _label, _pattern, f) in branches {
1423
+ nullable = nullable || f. recursion_check ( module, format_ref) ?;
1424
+ }
1425
+ Ok ( nullable)
1426
+ }
1427
+ Format :: Dynamic ( DynFormat :: Huffman ( _, _) ) => Ok ( true ) ,
1428
+ Format :: Apply ( _expr) => Ok ( false ) ,
1429
+ }
1430
+ }
1310
1431
}
1311
1432
1312
1433
impl Format {
0 commit comments