Skip to content

Commit 6decc60

Browse files
committed
Recursive formats with infinite loop check.
1 parent 5fce113 commit 6decc60

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

src/lib.rs

+121
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,14 @@ impl FormatModule {
527527
self.define_format_args(name, vec![], format)
528528
}
529529

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+
530538
pub fn define_format_args(
531539
&mut self,
532540
name: impl Into<String>,
@@ -549,6 +557,32 @@ impl FormatModule {
549557
FormatRef(level)
550558
}
551559

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+
552586
fn get_name(&self, level: usize) -> &str {
553587
&self.names[level]
554588
}
@@ -1307,6 +1341,93 @@ impl Format {
13071341
}
13081342
MatchTree::build(module, &fs, Rc::new(Next::Empty)).is_none()
13091343
}
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+
}
13101431
}
13111432

13121433
impl Format {

0 commit comments

Comments
 (0)