Update attenuations
This commit is contained in:
parent
12eaeb8f62
commit
833be7b293
|
@ -101,7 +101,7 @@ pub enum Expr {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
enum RewriteTemplate {
|
||||
Filter {
|
||||
Accept {
|
||||
pattern_template: AnyValue,
|
||||
},
|
||||
Rewrite {
|
||||
|
@ -110,6 +110,16 @@ enum RewriteTemplate {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum CaveatTemplate {
|
||||
Alts {
|
||||
alternatives: Vec<RewriteTemplate>,
|
||||
},
|
||||
Reject {
|
||||
pattern_template: AnyValue,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Symbolic {
|
||||
Reference(String),
|
||||
|
@ -174,55 +184,77 @@ fn tlit(value: AnyValue) -> sturdy::Template {
|
|||
sturdy::Template::Lit(Box::new(sturdy::Lit { value }))
|
||||
}
|
||||
|
||||
fn parse_attenuation(r: &Record<AnyValue>) -> io::Result<Option<(String, Vec<RewriteTemplate>)>> {
|
||||
fn parse_rewrite(raw_base_name: &AnyValue, e: &AnyValue) -> io::Result<RewriteTemplate> {
|
||||
if let Some(fields) = e.value().as_simple_record("accept", Some(1)) {
|
||||
return Ok(RewriteTemplate::Accept {
|
||||
pattern_template: fields[0].clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(fields) = e.value().as_simple_record("rewrite", Some(2)) {
|
||||
return Ok(RewriteTemplate::Rewrite {
|
||||
pattern_template: fields[0].clone(),
|
||||
template_template: fields[1].clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Err(bad_instruction(&format!("Bad rewrite in attenuation of {:?}: {:?}", raw_base_name, e)))
|
||||
}
|
||||
|
||||
fn parse_caveat(raw_base_name: &AnyValue, e: &AnyValue) -> io::Result<CaveatTemplate> {
|
||||
if let Some(fields) = e.value().as_simple_record("or", Some(1)) {
|
||||
let raw_rewrites = match fields[0].value().as_sequence() {
|
||||
None => Err(bad_instruction(&format!(
|
||||
"Alternatives in <or> in attenuation of {:?} must have sequence of rewrites; got {:?}",
|
||||
raw_base_name,
|
||||
fields[0])))?,
|
||||
Some(vs) => vs,
|
||||
};
|
||||
let alternatives =
|
||||
raw_rewrites.iter().map(|r| parse_rewrite(raw_base_name, r)).collect::<Result<Vec<_>, _>>()?;
|
||||
return Ok(CaveatTemplate::Alts{ alternatives });
|
||||
}
|
||||
|
||||
if let Some(fields) = e.value().as_simple_record("reject", Some(1)) {
|
||||
return Ok(CaveatTemplate::Reject{ pattern_template: fields[0].clone() });
|
||||
}
|
||||
|
||||
if let Ok(r) = parse_rewrite(raw_base_name, e) {
|
||||
return Ok(CaveatTemplate::Alts { alternatives: vec![r] });
|
||||
}
|
||||
|
||||
Err(bad_instruction(&format!("Bad caveat in attenuation of {:?}: {:?}", raw_base_name, e)))
|
||||
}
|
||||
|
||||
fn parse_attenuation(r: &Record<AnyValue>) -> io::Result<Option<(String, Vec<CaveatTemplate>)>> {
|
||||
if r.label() != &AnyValue::symbol("*") {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if r.fields().len() != 2 {
|
||||
Err(bad_instruction(&format!(
|
||||
"Attenuation requires a reference and a sequence of rewrites; got {:?}",
|
||||
"Attenuation requires a reference and a sequence of caveats; got {:?}",
|
||||
r)))?;
|
||||
}
|
||||
|
||||
let base_name = match r.fields()[0].value().as_symbol().map(|s| analyze(&s)) {
|
||||
let raw_base_name = &r.fields()[0];
|
||||
let base_name = match raw_base_name.value().as_symbol().map(|s| analyze(&s)) {
|
||||
Some(Symbolic::Reference(s)) => s,
|
||||
_ => Err(bad_instruction(&format!(
|
||||
"Attenuation must have variable reference as first argument; got {:?}",
|
||||
r.fields()[0])))?,
|
||||
raw_base_name)))?,
|
||||
};
|
||||
|
||||
let raw_alternatives = match r.fields()[1].value().as_sequence() {
|
||||
let raw_caveats = match r.fields()[1].value().as_sequence() {
|
||||
None => Err(bad_instruction(&format!(
|
||||
"Attenuation of {:?} must have sequence of rewrites; got {:?}",
|
||||
r.fields()[0],
|
||||
"Attenuation of {:?} must have sequence of caveats; got {:?}",
|
||||
raw_base_name,
|
||||
r.fields()[1])))?,
|
||||
Some(vs) => vs,
|
||||
};
|
||||
|
||||
let mut alternatives = Vec::new();
|
||||
|
||||
for e in raw_alternatives.iter() {
|
||||
match e.value().as_simple_record("filter", Some(1)) {
|
||||
Some(fields) =>
|
||||
alternatives.push(RewriteTemplate::Filter {
|
||||
pattern_template: fields[0].clone()
|
||||
}),
|
||||
None => match e.value().as_simple_record("rewrite", Some(2)) {
|
||||
Some(fields) =>
|
||||
alternatives.push(RewriteTemplate::Rewrite {
|
||||
pattern_template: fields[0].clone(),
|
||||
template_template: fields[1].clone(),
|
||||
}),
|
||||
None => Err(bad_instruction(&format!(
|
||||
"Bad rewrite in attenuation of {:?}: {:?}",
|
||||
r.fields()[0],
|
||||
e)))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some((base_name, alternatives)))
|
||||
let caveats = raw_caveats.iter().map(|c| parse_caveat(raw_base_name, c)).collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(Some((base_name, caveats)))
|
||||
}
|
||||
|
||||
impl<'env> PatternInstantiator<'env> {
|
||||
|
@ -250,8 +282,8 @@ impl<'env> PatternInstantiator<'env> {
|
|||
},
|
||||
|
||||
Value::Record(r) => match parse_attenuation(r)? {
|
||||
Some((base_name, alternatives)) =>
|
||||
dlit(self.env.eval_attenuation(base_name, alternatives)?),
|
||||
Some((base_name, caveats)) =>
|
||||
dlit(self.env.eval_attenuation(base_name, caveats)?),
|
||||
None => match self.maybe_binder_with_pattern(r)? {
|
||||
Some(pat) => pat,
|
||||
None => {
|
||||
|
@ -359,8 +391,8 @@ impl Env {
|
|||
},
|
||||
|
||||
Value::Record(r) => match parse_attenuation(r)? {
|
||||
Some((base_name, alternatives)) =>
|
||||
self.eval_attenuation(base_name, alternatives)?,
|
||||
Some((base_name, caveats)) =>
|
||||
self.eval_attenuation(base_name, caveats)?,
|
||||
None =>
|
||||
Value::Record(Record(r.fields_vec().iter().map(|a| self.instantiate_value(a))
|
||||
.collect::<Result<Vec<_>, _>>()?)).wrap(),
|
||||
|
@ -398,7 +430,7 @@ impl Env {
|
|||
fn eval_attenuation(
|
||||
&self,
|
||||
base_name: String,
|
||||
alternatives: Vec<RewriteTemplate>,
|
||||
caveats: Vec<CaveatTemplate>,
|
||||
) -> io::Result<AnyValue> {
|
||||
let base_value = self.lookup(&base_name, "attenuation-base variable")?;
|
||||
match base_value.value().as_embedded() {
|
||||
|
@ -406,9 +438,7 @@ impl Env {
|
|||
"Value to be attenuated is {:?} but must be capability",
|
||||
base_value))),
|
||||
Some(base_cap) => {
|
||||
match base_cap.attenuate(&sturdy::Attenuation(vec![
|
||||
self.instantiate_caveat(&alternatives)?]))
|
||||
{
|
||||
match base_cap.attenuate(&caveats.iter().map(|c| self.instantiate_caveat(c)).collect::<Result<Vec<_>, _>>()?) {
|
||||
Ok(derived_cap) => Ok(AnyValue::domain(derived_cap)),
|
||||
Err(caveat_error) =>
|
||||
Err(bad_instruction(&format!("Attenuation of {:?} failed: {:?}",
|
||||
|
@ -517,35 +547,50 @@ impl Env {
|
|||
}
|
||||
}
|
||||
|
||||
fn instantiate_caveat(
|
||||
fn instantiate_rewrite(
|
||||
&self,
|
||||
alternatives: &Vec<RewriteTemplate>,
|
||||
) -> io::Result<sturdy::Caveat> {
|
||||
let mut rewrites = Vec::new();
|
||||
for rw in alternatives {
|
||||
match rw {
|
||||
RewriteTemplate::Filter { pattern_template } => {
|
||||
let (_binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||
rewrites.push(sturdy::Rewrite {
|
||||
pattern: embed_pattern(&P::Pattern::DBind(Box::new(P::DBind { pattern }))),
|
||||
template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: 0.into() })),
|
||||
})
|
||||
}
|
||||
RewriteTemplate::Rewrite { pattern_template, template_template } => {
|
||||
let (binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||
rewrites.push(sturdy::Rewrite {
|
||||
pattern: embed_pattern(&pattern),
|
||||
template: self.instantiate_template(&binding_names, template_template)?,
|
||||
})
|
||||
}
|
||||
rw: &RewriteTemplate,
|
||||
) -> io::Result<sturdy::Rewrite> {
|
||||
match rw {
|
||||
RewriteTemplate::Accept { pattern_template } => {
|
||||
let (_binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||
Ok(sturdy::Rewrite {
|
||||
pattern: embed_pattern(&P::Pattern::DBind(Box::new(P::DBind { pattern }))),
|
||||
template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: 0.into() })),
|
||||
})
|
||||
}
|
||||
RewriteTemplate::Rewrite { pattern_template, template_template } => {
|
||||
let (binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||
Ok(sturdy::Rewrite {
|
||||
pattern: embed_pattern(&pattern),
|
||||
template: self.instantiate_template(&binding_names, template_template)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
if rewrites.len() == 1 {
|
||||
Ok(sturdy::Caveat::Rewrite(Box::new(rewrites.pop().unwrap())))
|
||||
} else {
|
||||
Ok(sturdy::Caveat::Alts(Box::new(sturdy::Alts {
|
||||
alternatives: rewrites,
|
||||
})))
|
||||
}
|
||||
|
||||
fn instantiate_caveat(
|
||||
&self,
|
||||
c: &CaveatTemplate,
|
||||
) -> io::Result<sturdy::Caveat> {
|
||||
match c {
|
||||
CaveatTemplate::Alts { alternatives } => {
|
||||
let mut rewrites =
|
||||
alternatives.iter().map(|r| self.instantiate_rewrite(r)).collect::<Result<Vec<_>, _>>()?;
|
||||
if rewrites.len() == 1 {
|
||||
Ok(sturdy::Caveat::Rewrite(Box::new(rewrites.pop().unwrap())))
|
||||
} else {
|
||||
Ok(sturdy::Caveat::Alts(Box::new(sturdy::Alts {
|
||||
alternatives: rewrites,
|
||||
})))
|
||||
}
|
||||
}
|
||||
CaveatTemplate::Reject { pattern_template } => {
|
||||
Ok(sturdy::Caveat::Reject(Box::new(
|
||||
sturdy::Reject {
|
||||
pattern: embed_pattern(&self.instantiate_pattern(pattern_template)?.1),
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,18 +629,19 @@ impl Env {
|
|||
},
|
||||
|
||||
Value::Record(r) => match parse_attenuation(r)? {
|
||||
Some((base_name, alternatives)) =>
|
||||
Some((base_name, caveats)) =>
|
||||
match find_bound(&base_name) {
|
||||
Some(i) =>
|
||||
sturdy::Template::TAttenuate(Box::new(sturdy::TAttenuate {
|
||||
template: sturdy::Template::TRef(Box::new(sturdy::TRef {
|
||||
binding: i.into(),
|
||||
})),
|
||||
attenuation: sturdy::Attenuation(vec![
|
||||
self.instantiate_caveat(&alternatives)?]),
|
||||
attenuation: caveats.iter()
|
||||
.map(|c| self.instantiate_caveat(c))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
})),
|
||||
None =>
|
||||
tlit(self.eval_attenuation(base_name, alternatives)?),
|
||||
tlit(self.eval_attenuation(base_name, caveats)?),
|
||||
},
|
||||
None => {
|
||||
// TODO: properly consolidate constant templates into literals.
|
||||
|
|
|
@ -2270,11 +2270,11 @@ impl Cap {
|
|||
}
|
||||
|
||||
/// Yields a fresh `Cap` for `self`'s `underlying`, copying the
|
||||
/// existing attenuation of `self` to the new `Cap` and adding
|
||||
/// `attenuation` to it.
|
||||
pub fn attenuate(&self, attenuation: &sturdy::Attenuation) -> Result<Arc<Self>, CaveatError> {
|
||||
/// existing attenuation of `self` to the new `Cap` and adding the
|
||||
/// `caveats` to it.
|
||||
pub fn attenuate(&self, caveats: &[sturdy::Caveat]) -> Result<Arc<Self>, CaveatError> {
|
||||
let mut r = Cap { attenuation: self.attenuation.clone(), .. self.clone() };
|
||||
r.attenuation.extend(attenuation.check()?);
|
||||
r.attenuation.extend(sturdy::Caveat::check_many(caveats)?);
|
||||
Ok(Arc::new(r))
|
||||
}
|
||||
|
||||
|
@ -2282,7 +2282,7 @@ impl Cap {
|
|||
/// `a` is filtered out, or `Some(_)` if it is accepted (and
|
||||
/// possibly transformed).
|
||||
pub fn rewrite(&self, mut a: AnyValue) -> Option<AnyValue> {
|
||||
for c in &self.attenuation {
|
||||
for c in self.attenuation.iter().rev() {
|
||||
match c.rewrite(&a) {
|
||||
Some(v) => a = v,
|
||||
None => return None,
|
||||
|
|
|
@ -580,7 +580,7 @@ impl Membranes {
|
|||
match self.exported.oid_map.get(&oid) {
|
||||
None => self.exported.insert_inert_entity(t, oid),
|
||||
Some(ws) => {
|
||||
let attenuated_obj = ws.obj.attenuate(&sturdy::Attenuation(attenuation))
|
||||
let attenuated_obj = ws.obj.attenuate(&attenuation)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
|
|
|
@ -16,7 +16,10 @@ pub type CheckedRewrite = (usize, Pattern, Template);
|
|||
/// A safety-checked [`Caveat`]: none of the errors enumerated in
|
||||
/// `CaveatError` apply.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct CheckedCaveat { alts: Vec<CheckedRewrite> }
|
||||
pub enum CheckedCaveat {
|
||||
Alts(Vec<CheckedRewrite>),
|
||||
Reject(Pattern),
|
||||
}
|
||||
|
||||
/// Represents any detected error in a [`Caveat`]; that is, in a
|
||||
/// [`Pattern`] or a [`Template`].
|
||||
|
@ -28,43 +31,44 @@ pub enum CaveatError {
|
|||
BindingUnderNegation,
|
||||
}
|
||||
|
||||
impl Attenuation {
|
||||
/// Yields `Ok(())` iff `self` has no [`CaveatError`].
|
||||
pub fn validate(&self) -> Result<(), CaveatError> {
|
||||
for c in &self.0 { c.validate()? }
|
||||
impl Caveat {
|
||||
/// Yields `Ok(())` iff `caveats` have no [`CaveatError`].
|
||||
pub fn validate_many(caveats: &[Caveat]) -> Result<(), CaveatError> {
|
||||
for c in caveats { c.validate()? }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Yields a vector of [`CheckedCaveat`s][CheckedCaveat] iff
|
||||
/// `self` has no [`CaveatError`].
|
||||
pub fn check(&self) -> Result<Vec<CheckedCaveat>, CaveatError> {
|
||||
self.0.iter().map(Caveat::check).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Caveat {
|
||||
/// Yields `Ok(())` iff `self` has no [`CaveatError`].
|
||||
pub fn validate(&self) -> Result<(), CaveatError> {
|
||||
match self {
|
||||
Caveat::Rewrite(b) => (&**b).validate(),
|
||||
Caveat::Alts(b) => (&**b).alternatives.iter().map(Rewrite::validate).collect::<Result<(), _>>(),
|
||||
Caveat::Reject(_) => Ok(()),
|
||||
Caveat::Unknown(_) => Ok(()), /* it's valid to have unknown caveats, they just won't pass anything */
|
||||
}
|
||||
}
|
||||
|
||||
/// Yields a vector of [`CheckedCaveat`s][CheckedCaveat] iff
|
||||
/// `caveats` have no [`CaveatError`].
|
||||
pub fn check_many(caveats: &[Caveat]) -> Result<Vec<CheckedCaveat>, CaveatError> {
|
||||
caveats.iter().map(Caveat::check).collect()
|
||||
}
|
||||
|
||||
/// Yields a [`CheckedCaveat`] iff `self` has no [`CaveatError`].
|
||||
pub fn check(&self) -> Result<CheckedCaveat, CaveatError> {
|
||||
match self {
|
||||
Caveat::Rewrite(b) =>
|
||||
Ok(CheckedCaveat {
|
||||
alts: vec![ (*b).check()? ]
|
||||
}),
|
||||
Ok(CheckedCaveat::Alts(vec![ (*b).check()? ])),
|
||||
Caveat::Alts(b) => {
|
||||
let Alts { alternatives } = &**b;
|
||||
Ok(CheckedCaveat {
|
||||
alts: alternatives.into_iter().map(Rewrite::check)
|
||||
.collect::<Result<Vec<CheckedRewrite>, CaveatError>>()?
|
||||
})
|
||||
Ok(CheckedCaveat::Alts(
|
||||
alternatives.into_iter().map(Rewrite::check)
|
||||
.collect::<Result<Vec<CheckedRewrite>, CaveatError>>()?))
|
||||
}
|
||||
Caveat::Reject(b) =>
|
||||
Ok(CheckedCaveat::Reject(b.pattern.clone())),
|
||||
Caveat::Unknown(_) =>
|
||||
Ok(CheckedCaveat::Reject(Pattern::PDiscard(Box::new(PDiscard)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +191,7 @@ impl Template {
|
|||
match self {
|
||||
Template::TAttenuate(b) => {
|
||||
let TAttenuate { template, attenuation } = &**b;
|
||||
attenuation.validate()?;
|
||||
Caveat::validate_many(attenuation)?;
|
||||
Ok(template.implied_binding_count()?)
|
||||
}
|
||||
Template::TRef(b) => match usize::try_from(&(&**b).binding) {
|
||||
|
@ -273,12 +277,24 @@ impl Rewrite {
|
|||
impl CheckedCaveat {
|
||||
/// Rewrites `a` using the patterns/templates contained in `self`.
|
||||
pub fn rewrite(&self, a: &_Any) -> Option<_Any> {
|
||||
for (n, p, t) in &self.alts {
|
||||
let mut bindings = Vec::with_capacity(*n);
|
||||
if let true = p.matches(a, &mut bindings) {
|
||||
return t.instantiate(&bindings);
|
||||
match self {
|
||||
CheckedCaveat::Alts(alts) => {
|
||||
for (n, p, t) in alts {
|
||||
let mut bindings = Vec::with_capacity(*n);
|
||||
if p.matches(a, &mut bindings) {
|
||||
return t.instantiate(&bindings);
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
CheckedCaveat::Reject(pat) => {
|
||||
let mut bindings = Vec::with_capacity(0);
|
||||
if pat.matches(a, &mut bindings) {
|
||||
None
|
||||
} else {
|
||||
Some(a.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,14 @@ fn signature(key: &[u8], data: &[u8]) -> Vec<u8> {
|
|||
result
|
||||
}
|
||||
|
||||
fn chain_signature(key: &[u8], chain: &[Caveat]) -> Vec<u8> {
|
||||
let mut key = key.to_vec();
|
||||
for c in chain {
|
||||
key = signature(&key, &encode(&language().unparse(c)));
|
||||
}
|
||||
key
|
||||
}
|
||||
|
||||
pub fn new_key() -> Vec<u8> {
|
||||
let mut buf = vec![0; KEY_LENGTH];
|
||||
getrandom(&mut buf).expect("successful random number generation");
|
||||
|
@ -83,24 +91,15 @@ impl SturdyRef {
|
|||
unattenuated_target: &_Ptr,
|
||||
) -> Result<_Ptr, ValidationError> {
|
||||
self.validate(key).map_err(ValidationError::SignatureError)?;
|
||||
let mut attenuation = Vec::new();
|
||||
// TODO:: Make sure of the ordering here!!
|
||||
for a in self.caveat_chain.iter().rev() {
|
||||
attenuation.extend(a.0.iter().rev().cloned());
|
||||
}
|
||||
let target = unattenuated_target
|
||||
.attenuate(&Attenuation(attenuation))
|
||||
.attenuate(&self.caveat_chain)
|
||||
.map_err(ValidationError::AttenuationError)?;
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
pub fn validate(&self, key: &[u8]) -> Result<(), MacError> {
|
||||
let SturdyRef { oid, caveat_chain, sig } = self;
|
||||
let mut key = key.to_vec();
|
||||
key = signature(&key, &encode(oid));
|
||||
for c in caveat_chain {
|
||||
key = signature(&key, &encode(&language().unparse(c)));
|
||||
}
|
||||
let key = chain_signature(&signature(&key, &encode(oid)), caveat_chain);
|
||||
if &key == sig {
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -108,13 +107,13 @@ impl SturdyRef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn attenuate(&self, attenuation: &Attenuation) -> Result<Self, CaveatError> {
|
||||
attenuation.validate()?;
|
||||
pub fn attenuate(&self, attenuation: &[Caveat]) -> Result<Self, CaveatError> {
|
||||
Caveat::validate_many(attenuation)?;
|
||||
let SturdyRef { oid, caveat_chain, sig } = self;
|
||||
let oid = oid.clone();
|
||||
let mut caveat_chain = caveat_chain.clone();
|
||||
caveat_chain.push(attenuation.clone());
|
||||
let sig = signature(&sig, &encode(&language().unparse(attenuation)));
|
||||
caveat_chain.extend(attenuation.iter().cloned());
|
||||
let sig = chain_signature(&sig, attenuation);
|
||||
Ok(SturdyRef { oid, caveat_chain, sig })
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue