Skip to content

Commit e61707a

Browse files
committed
Add read_repeat_until_full primitive
1 parent 5a55785 commit e61707a

File tree

5 files changed

+89
-1
lines changed

5 files changed

+89
-1
lines changed

fathom/src/core.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ def_prims! {
373373
FormatArray64 => "array64",
374374
/// Repeat a format until the length of the given parse scope is reached.
375375
FormatRepeatUntilEnd => "repeat_until_end",
376+
/// Repeat a format until the array is filled.
377+
///
378+
/// The value read by the format is replicated according to a supplied function.
379+
FormatRepeatUntilFull => "repeat_until_full",
376380
/// Limit the format to an unsigned 8-bit byte length.
377381
FormatLimit8 => "limit8",
378382
/// Limit the format to an unsigned 16-bit byte length.
@@ -442,6 +446,7 @@ def_prims! {
442446
U16And => "u16_and",
443447
U16Or => "u16_or",
444448
U16Xor => "u16_xor",
449+
U16FromU8 => "u16_from_u8",
445450

446451
U32Eq => "u32_eq",
447452
U32Neq => "u32_neq",

fathom/src/core/binary.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ impl<'arena, 'env, 'data> Context<'arena, 'env, 'data> {
416416
(Prim::FormatArray32, [FunApp(len), FunApp(format)]) => self.read_array(reader, span, len, format),
417417
(Prim::FormatArray64, [FunApp(len), FunApp(format)]) => self.read_array(reader, span, len, format),
418418
(Prim::FormatRepeatUntilEnd, [FunApp(format)]) => self.read_repeat_until_end(reader, format),
419+
(Prim::FormatRepeatUntilFull, [FunApp(len), FunApp(format), FunApp(replicate)]) => self.read_repeat_until_full(reader, len, replicate, format),
419420
(Prim::FormatLimit8, [FunApp(limit), FunApp(format)]) => self.read_limit(reader, limit, format),
420421
(Prim::FormatLimit16, [FunApp(limit), FunApp(format)]) => self.read_limit(reader, limit, format),
421422
(Prim::FormatLimit32, [FunApp(limit), FunApp(format)]) => self.read_limit(reader, limit, format),
@@ -485,6 +486,50 @@ impl<'arena, 'env, 'data> Context<'arena, 'env, 'data> {
485486
}
486487
}
487488

489+
fn read_repeat_until_full(
490+
&mut self,
491+
reader: &mut BufferReader<'data>,
492+
len: &ArcValue<'arena>,
493+
replicate: &ArcValue<'arena>,
494+
elem_format: &ArcValue<'arena>,
495+
) -> Result<ArcValue<'arena>, ReadError<'arena>> {
496+
let len = match self.elim_env().force(len).as_ref() {
497+
Value::ConstLit(Const::U8(len, _)) => Some(usize::from(*len)),
498+
Value::ConstLit(Const::U16(len, _)) => Some(usize::from(*len)),
499+
Value::ConstLit(Const::U32(len, _)) => usize::try_from(*len).ok(),
500+
Value::ConstLit(Const::U64(len, _)) => usize::try_from(*len).ok(),
501+
_ => return Err(ReadError::InvalidValue(len.span())),
502+
}
503+
.ok_or_else(|| ReadError::InvalidValue(len.span()))?;
504+
505+
// TODO: Do we need to force replicate as well?
506+
// let replicate = self.elim_env().force(replicate);
507+
508+
let mut elems = Vec::with_capacity(len);
509+
while elems.len() < len {
510+
match self.read_format(reader, elem_format) {
511+
Ok(elem) => {
512+
// Call the function to determine how many items this represents
513+
let closure_res = self.elim_env().fun_app(replicate.clone(), elem.clone());
514+
let repeat = match closure_res.as_ref() {
515+
Value::ConstLit(Const::U16(n, _)) => *n,
516+
_ => return Err(ReadError::InvalidValue(replicate.span())),
517+
};
518+
519+
// Push it that many times onto the array
520+
// TODO: Error/limit if this exceeds len?
521+
elems.extend(std::iter::repeat(elem).take(usize::from(repeat)));
522+
}
523+
Err(err) => return Err(err),
524+
};
525+
}
526+
527+
Ok(Spanned::new(
528+
elem_format.span(),
529+
Arc::new(Value::ArrayLit(elems)),
530+
))
531+
}
532+
488533
fn read_limit(
489534
&mut self,
490535
reader: &BufferReader<'data>,

fathom/src/core/semantics.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ fn prim_step(prim: Prim) -> Option<PrimStep> {
475475
Prim::U16And => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitand(*x, *y), UIntStyle::merge(*xst, *yst))),
476476
Prim::U16Or => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitor(*x, *y), UIntStyle::merge(*xst, *yst))),
477477
Prim::U16Xor => const_step!([x, xst: U16, y, yst: U16] => Const::U16(u16::bitxor(*x, *y), UIntStyle::merge(*xst, *yst))),
478+
Prim::U16FromU8 => const_step!([x, xst: U8] => Const::U16(u16::from(*x), *xst)),
478479

479480
Prim::U32Eq => const_step!([x: U32, y: U32] => Const::Bool(x == y)),
480481
Prim::U32Neq => const_step!([x: U32, y: U32] => Const::Bool(x != y)),
@@ -856,13 +857,18 @@ impl<'arena, 'env> ElimEnv<'arena, 'env> {
856857
(Prim::FormatRepeatUntilEnd, [Elim::FunApp(elem)]) => {
857858
Value::prim(Prim::ArrayType, [self.format_repr(elem)])
858859
}
860+
(Prim::FormatRepeatUntilFull, [Elim::FunApp(len), _, Elim::FunApp(elem)]) => {
861+
Value::prim(Prim::Array16Type, [len.clone(), self.format_repr(elem)])
862+
}
859863
(Prim::FormatLink, [_, Elim::FunApp(elem)]) => {
860864
Value::prim(Prim::RefType, [elem.clone()])
861865
}
862866
(Prim::FormatDeref, [Elim::FunApp(elem), _]) => return self.format_repr(elem),
863867
(Prim::FormatStreamPos, []) => Value::prim(Prim::PosType, []),
864868
(Prim::FormatSucceed, [Elim::FunApp(elem), _]) => return elem.clone(),
865-
(Prim::FormatOrSucceed, [_, Elim::FunApp(elem), _]) => return self.format_repr(elem),
869+
(Prim::FormatOrSucceed, [_, Elim::FunApp(elem), _]) => {
870+
return self.format_repr(elem)
871+
}
866872
(Prim::FormatFail, []) => Value::prim(Prim::VoidType, []),
867873
(Prim::FormatUnwrap, [Elim::FunApp(elem), _]) => return elem.clone(),
868874
(Prim::ReportedError, []) => Value::prim(Prim::ReportedError, []),

fathom/src/surface/elaboration.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,35 @@ impl<'arena> RigidEnv<'arena> {
187187
env.define_prim_fun(FormatArray32, [&U32_TYPE, &FORMAT_TYPE], &FORMAT_TYPE);
188188
env.define_prim_fun(FormatArray64, [&U64_TYPE, &FORMAT_TYPE], &FORMAT_TYPE);
189189
env.define_prim_fun(FormatRepeatUntilEnd, [&FORMAT_TYPE], &FORMAT_TYPE);
190+
// repeat_until_full16 : U16 -> fun (A : Format) -> (Repr A -> U16) -> Format
191+
env.define_prim(
192+
FormatRepeatUntilFull,
193+
scope.to_scope(core::Term::FunType(
194+
Span::Empty,
195+
None,
196+
&U16_TYPE,
197+
scope.to_scope(core::Term::FunType(
198+
Span::Empty,
199+
env.name("A"),
200+
&FORMAT_TYPE,
201+
scope.to_scope(core::Term::FunType(
202+
Span::Empty,
203+
None,
204+
scope.to_scope(Term::FunType(
205+
Span::Empty,
206+
None,
207+
scope.to_scope(Term::FunApp(
208+
Span::Empty,
209+
&Term::Prim(Span::Empty, FormatRepr),
210+
&VAR0,
211+
)),
212+
&U16_TYPE,
213+
)),
214+
&FORMAT_TYPE,
215+
)),
216+
)),
217+
)),
218+
);
190219
env.define_prim_fun(FormatLimit8, [&U8_TYPE, &FORMAT_TYPE], &FORMAT_TYPE);
191220
env.define_prim_fun(FormatLimit16, [&U16_TYPE, &FORMAT_TYPE], &FORMAT_TYPE);
192221
env.define_prim_fun(FormatLimit32, [&U32_TYPE, &FORMAT_TYPE], &FORMAT_TYPE);
@@ -294,6 +323,7 @@ impl<'arena> RigidEnv<'arena> {
294323
env.define_prim_fun(U16And, [&U16_TYPE, &U16_TYPE], &U16_TYPE);
295324
env.define_prim_fun(U16Or, [&U16_TYPE, &U16_TYPE], &U16_TYPE);
296325
env.define_prim_fun(U16Xor, [&U16_TYPE, &U16_TYPE], &U16_TYPE);
326+
env.define_prim_fun(U16FromU8, [&U8_TYPE], &U16_TYPE);
297327

298328
env.define_prim_fun(U32Eq, [&U32_TYPE, &U32_TYPE], &BOOL_TYPE);
299329
env.define_prim_fun(U32Neq, [&U32_TYPE, &U32_TYPE], &BOOL_TYPE);

tests/succeed/primitives.fathom

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ let _ = array16 : U16 -> Format -> Format;
5656
let _ = array32 : U32 -> Format -> Format;
5757
let _ = array64 : U64 -> Format -> Format;
5858
let _ = repeat_until_end : Format -> Format;
59+
let _ = repeat_until_full : U16 -> fun (A : Format) -> (Repr A -> U16) -> Format;
5960
let _ = array8 : U8 -> Format -> Format;
6061
let _ = array16 : U16 -> Format -> Format;
6162
let _ = array32 : U32 -> Format -> Format;
@@ -108,6 +109,7 @@ let _ = u16_shr : U16 -> U8 -> U16;
108109
let _ = u16_and : U16 -> U16 -> U16;
109110
let _ = u16_or : U16 -> U16 -> U16;
110111
let _ = u16_xor : U16 -> U16 -> U16;
112+
let _ = u16_from_u8 : U8 -> U16;
111113

112114
let _ = u32_eq : U32 -> U32 -> Bool;
113115
let _ = u32_neq : U32 -> U32 -> Bool;

0 commit comments

Comments
 (0)