WIP: add new opcodes to Air and AirTree and update parts of codegen to handle the new pair type

This commit is contained in:
microproofs 2024-03-18 14:24:41 -04:00 committed by Kasey
parent 9e78f0fc2a
commit f950ae7d3d
5 changed files with 548 additions and 143 deletions

View File

@ -1091,6 +1091,7 @@ impl<'a> CodeGenerator<'a> {
tipo: constr_tipo, tipo: constr_tipo,
.. ..
} => { } => {
// TODO: Implement Pair pattern
if tipo.is_bool() { if tipo.is_bool() {
assert!(props.kind.is_expect()); assert!(props.kind.is_expect());
@ -1364,12 +1365,13 @@ impl<'a> CodeGenerator<'a> {
msg_func.clone(), msg_func.clone(),
); );
let anon_func_body = AirTree::tuple_access( let anon_func_body = AirTree::pair_access(
vec![fst_name, snd_name], Some(fst_name),
Some(snd_name),
inner_list_type.clone(), inner_list_type.clone(),
AirTree::local_var(&pair_name, inner_list_type.clone()), AirTree::local_var(&pair_name, inner_list_type.clone()),
msg_func.clone(), msg_func.clone(),
msg_func.is_some(), true,
AirTree::let_assignment("_", expect_fst, expect_snd), AirTree::let_assignment("_", expect_fst, expect_snd),
); );
@ -1512,16 +1514,17 @@ impl<'a> CodeGenerator<'a> {
msg_func.clone(), msg_func.clone(),
); );
let tuple_access = AirTree::tuple_access( let pair_access = AirTree::pair_access(
vec![fst_name, snd_name], Some(fst_name.clone()),
Some(snd_name.clone()),
tipo.clone(), tipo.clone(),
AirTree::local_var(&pair_name, tipo.clone()), AirTree::local_var(&pair_name, tipo.clone()),
msg_func.clone(), msg_func.clone(),
msg_func.is_some(), true,
AirTree::let_assignment("_", expect_fst, expect_snd), AirTree::let_assignment("_", expect_fst, expect_snd),
); );
AirTree::let_assignment(&pair_name, value, tuple_access) AirTree::let_assignment(&pair_name, value, pair_access)
} else if tipo.is_tuple() { } else if tipo.is_tuple() {
let tuple_inner_types = tipo.get_inner_types(); let tuple_inner_types = tipo.get_inner_types();
@ -1799,6 +1802,7 @@ impl<'a> CodeGenerator<'a> {
} }
match &mut props.specific_clause { match &mut props.specific_clause {
// TODO: Implement PairClause and PairClauseGuard
SpecificClause::ConstrClause => { SpecificClause::ConstrClause => {
let data_type = lookup_data_type_by_tipo(&self.data_types, subject_tipo); let data_type = lookup_data_type_by_tipo(&self.data_types, subject_tipo);
@ -3845,7 +3849,7 @@ impl<'a> CodeGenerator<'a> {
DefaultFunction::MkCons | DefaultFunction::MkPairData => { DefaultFunction::MkCons | DefaultFunction::MkPairData => {
unimplemented!( unimplemented!(
"MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z).\n" "MkCons and MkPairData should be handled by an anon function or using [] or ( a, b, .., z) or Pair {{fst:a, snd: b}}.\n"
) )
} }
_ => { _ => {
@ -4792,31 +4796,49 @@ impl<'a> CodeGenerator<'a> {
.apply(next_clause.delay()); .apply(next_clause.delay());
} }
if tipo.is_pair() { for (index, name) in indices.iter() {
for (index, name) in indices.iter() { term = term.lambda(name.clone()).apply(builder::known_data_to_type(
if name == "_" { Term::head_list()
continue; .apply(Term::var(subject_name.clone()).repeat_tail_list(*index)),
} &tuple_types[*index].clone(),
let builtin = if *index == 0 { ));
Term::fst_pair()
} else {
Term::snd_pair()
};
term = term.lambda(name).apply(builder::known_data_to_type(
builtin.apply(Term::var(subject_name.clone())),
&tuple_types[*index].clone(),
));
}
} else {
for (index, name) in indices.iter() {
term = term.lambda(name.clone()).apply(builder::known_data_to_type(
Term::head_list()
.apply(Term::var(subject_name.clone()).repeat_tail_list(*index)),
&tuple_types[*index].clone(),
));
}
} }
Some(term)
}
Air::PairClause {
subject_tipo: tipo,
complex_clause,
subject_name,
fst_name,
snd_name,
} => {
let mut term = arg_stack.pop().unwrap();
let next_clause = arg_stack.pop().unwrap();
let pair_types = tipo.get_inner_types();
if complex_clause {
term = term
.lambda("__other_clauses_delayed")
.apply(next_clause.delay());
}
if let Some(fst) = fst_name {
term = term.lambda(fst).apply(builder::known_data_to_type(
Term::fst_pair().apply(Term::var(subject_name.clone())),
&pair_types[0].clone(),
));
}
if let Some(snd) = snd_name {
term = term.lambda(snd).apply(builder::known_data_to_type(
Term::snd_pair().apply(Term::var(subject_name.clone())),
&pair_types[1].clone(),
));
}
Some(term) Some(term)
} }
Air::ClauseGuard { Air::ClauseGuard {
@ -4913,31 +4935,40 @@ impl<'a> CodeGenerator<'a> {
let tuple_types = tipo.get_inner_types(); let tuple_types = tipo.get_inner_types();
if tuple_types.len() == 2 { for (index, name) in indices.iter() {
for (index, name) in indices.iter() { term = term.lambda(name.clone()).apply(builder::known_data_to_type(
if name == "_" { Term::head_list()
continue; .apply(Term::var(subject_name.clone()).repeat_tail_list(*index)),
} &tuple_types[*index].clone(),
let builtin = if *index == 0 { ));
Term::fst_pair()
} else {
Term::snd_pair()
};
term = term.lambda(name).apply(builder::known_data_to_type(
builtin.apply(Term::var(subject_name.clone())),
&tuple_types[*index].clone(),
));
}
} else {
for (index, name) in indices.iter() {
term = term.lambda(name.clone()).apply(builder::known_data_to_type(
Term::head_list()
.apply(Term::var(subject_name.clone()).repeat_tail_list(*index)),
&tuple_types[*index].clone(),
));
}
} }
Some(term)
}
Air::PairGuard {
subject_tipo: tipo,
subject_name,
fst_name,
snd_name,
} => {
let mut term = arg_stack.pop().unwrap();
let tuple_types = tipo.get_inner_types();
if let Some(fst) = fst_name {
term = term.lambda(fst).apply(builder::known_data_to_type(
Term::fst_pair().apply(Term::var(subject_name.clone())),
&tuple_types[0].clone(),
));
}
if let Some(snd) = snd_name {
term = term.lambda(snd).apply(builder::known_data_to_type(
Term::snd_pair().apply(Term::var(subject_name.clone())),
&tuple_types[1].clone(),
));
}
Some(term) Some(term)
} }
Air::Finally => { Air::Finally => {
@ -5094,34 +5125,9 @@ impl<'a> CodeGenerator<'a> {
if constants.len() == args.len() { if constants.len() == args.len() {
let data_constants = builder::convert_constants_to_data(constants); let data_constants = builder::convert_constants_to_data(constants);
if count == 2 { let term = Term::Constant(
let term = Term::Constant( UplcConstant::ProtoList(UplcType::Data, data_constants).into(),
UplcConstant::ProtoPair( );
UplcType::Data,
UplcType::Data,
data_constants[0].clone().into(),
data_constants[1].clone().into(),
)
.into(),
);
Some(term)
} else {
let term = Term::Constant(
UplcConstant::ProtoList(UplcType::Data, data_constants).into(),
);
Some(term)
}
} else if count == 2 {
let term = Term::mk_pair_data()
.apply(builder::convert_type_to_data(
args[0].clone(),
&tuple_sub_types[0],
))
.apply(builder::convert_type_to_data(
args[1].clone(),
&tuple_sub_types[1],
));
Some(term) Some(term)
} else { } else {
let mut term = Term::empty_list(); let mut term = Term::empty_list();
@ -5133,6 +5139,38 @@ impl<'a> CodeGenerator<'a> {
Some(term) Some(term)
} }
} }
Air::Pair { tipo } => {
let fst = arg_stack.pop().unwrap();
let snd = arg_stack.pop().unwrap();
match (extract_constant(&fst), extract_constant(&snd)) {
(Some(fst), Some(snd)) => {
let term = Term::Constant(
UplcConstant::ProtoPair(
UplcType::Data,
UplcType::Data,
fst.clone(),
snd.clone(),
)
.into(),
);
Some(term)
}
_ => {
let term = Term::mk_pair_data()
.apply(builder::convert_type_to_data(
fst,
&tipo.get_inner_types()[0],
))
.apply(builder::convert_type_to_data(
snd,
&tipo.get_inner_types()[1],
));
Some(term)
}
}
}
Air::RecordUpdate { Air::RecordUpdate {
highest_index, highest_index,
indices, indices,
@ -5261,67 +5299,75 @@ impl<'a> CodeGenerator<'a> {
let mut term = arg_stack.pop().unwrap(); let mut term = arg_stack.pop().unwrap();
let list_id = self.id_gen.next(); let list_id = self.id_gen.next();
if tipo.is_pair() { let mut id_list = vec![];
assert!(names.len() == 2); id_list.push(list_id);
if names[1] != "_" { names.iter().for_each(|_| {
term = term.lambda(names[1].clone()).apply(if is_expect { id_list.push(self.id_gen.next());
convert_data_to_type( });
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
&inner_types[1],
)
} else {
known_data_to_type(
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
&inner_types[1],
)
});
}
if names[0] != "_" { let names_types = names
term = term.lambda(names[0].clone()).apply(if is_expect { .into_iter()
convert_data_to_type( .zip(inner_types)
Term::fst_pair().apply(Term::var(format!("__tuple_{list_id}"))), .zip(id_list)
&inner_types[0], .map(|((name, tipo), id)| (name, tipo, id))
) .collect_vec();
} else {
known_data_to_type(
Term::fst_pair().apply(Term::var(format!("__tuple_{list_id}"))),
&inner_types[0],
)
})
}
term = term.lambda(format!("__tuple_{list_id}")).apply(value); term = builder::list_access_to_uplc(
&names_types,
false,
term,
false,
is_expect.into(),
error_term,
)
.apply(value);
Some(term) Some(term)
} else { }
let mut id_list = vec![]; Air::PairAccessor {
id_list.push(list_id); fst,
snd,
tipo,
is_expect,
} => {
let inner_types = tipo.get_inner_types();
let value = arg_stack.pop().unwrap();
names.iter().for_each(|_| { let mut term = arg_stack.pop().unwrap();
id_list.push(self.id_gen.next()); let list_id = self.id_gen.next();
if let Some(name) = snd {
term = term.lambda(name).apply(if is_expect {
convert_data_to_type(
Term::snd_pair().apply(Term::var(format!("__pair_{list_id}"))),
&inner_types[1],
)
} else {
known_data_to_type(
Term::snd_pair().apply(Term::var(format!("__pair_{list_id}"))),
&inner_types[1],
)
}); });
let names_types = names
.into_iter()
.zip(inner_types)
.zip(id_list)
.map(|((name, tipo), id)| (name, tipo, id))
.collect_vec();
term = builder::list_access_to_uplc(
&names_types,
false,
term,
false,
is_expect.into(),
error_term,
)
.apply(value);
Some(term)
} }
if let Some(name) = fst {
term = term.lambda(name).apply(if is_expect {
convert_data_to_type(
Term::fst_pair().apply(Term::var(format!("__pair_{list_id}"))),
&inner_types[0],
)
} else {
known_data_to_type(
Term::fst_pair().apply(Term::var(format!("__pair_{list_id}"))),
&inner_types[0],
)
})
}
term = term.lambda(format!("__pair_{list_id}")).apply(value);
Some(term)
} }
Air::Trace { .. } => { Air::Trace { .. } => {
let text = arg_stack.pop().unwrap(); let text = arg_stack.pop().unwrap();

View File

@ -51,6 +51,9 @@ pub enum Air {
tipo: Rc<Type>, tipo: Rc<Type>,
count: usize, count: usize,
}, },
Pair {
tipo: Rc<Type>,
},
Void, Void,
Var { Var {
constructor: ValueConstructor, constructor: ValueConstructor,
@ -136,6 +139,13 @@ pub enum Air {
subject_name: String, subject_name: String,
complex_clause: bool, complex_clause: bool,
}, },
PairClause {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
complex_clause: bool,
},
ClauseGuard { ClauseGuard {
subject_name: String, subject_name: String,
subject_tipo: Rc<Type>, subject_tipo: Rc<Type>,
@ -151,6 +161,12 @@ pub enum Air {
indices: IndexSet<(usize, String)>, indices: IndexSet<(usize, String)>,
subject_name: String, subject_name: String,
}, },
PairGuard {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
},
Finally, Finally,
// If // If
If { If {
@ -190,6 +206,13 @@ pub enum Air {
tipo: Rc<Type>, tipo: Rc<Type>,
is_expect: bool, is_expect: bool,
}, },
// Tuple Access
PairAccessor {
fst: Option<String>,
snd: Option<String>,
tipo: Rc<Type>,
is_expect: bool,
},
// Misc. // Misc.
ErrorTerm { ErrorTerm {
tipo: Rc<Type>, tipo: Rc<Type>,

View File

@ -1852,6 +1852,7 @@ pub fn air_holds_msg(air: &Air) -> bool {
Air::FieldsExpose { is_expect, .. } Air::FieldsExpose { is_expect, .. }
| Air::TupleAccessor { is_expect, .. } | Air::TupleAccessor { is_expect, .. }
| Air::PairAccessor { is_expect, .. }
| Air::CastFromData { is_expect, .. } => *is_expect, | Air::CastFromData { is_expect, .. } => *is_expect,
Air::ListAccessor { expect_level, .. } => { Air::ListAccessor { expect_level, .. } => {

View File

@ -162,6 +162,13 @@ pub enum AirTree {
subject_name: String, subject_name: String,
then: Box<AirTree>, then: Box<AirTree>,
}, },
PairGuard {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
then: Box<AirTree>,
},
// Field Access // Field Access
FieldsExpose { FieldsExpose {
indices: Vec<(usize, String, Rc<Type>)>, indices: Vec<(usize, String, Rc<Type>)>,
@ -195,6 +202,16 @@ pub enum AirTree {
msg: Option<AirMsg>, msg: Option<AirMsg>,
then: Box<AirTree>, then: Box<AirTree>,
}, },
// Pair Access
PairAccessor {
fst: Option<String>,
snd: Option<String>,
tipo: Rc<Type>,
is_expect: bool,
msg: Option<AirMsg>,
pair: Box<AirTree>,
then: Box<AirTree>,
},
// Misc. // Misc.
FieldsEmpty { FieldsEmpty {
constr: Box<AirTree>, constr: Box<AirTree>,
@ -237,6 +254,11 @@ pub enum AirTree {
tipo: Rc<Type>, tipo: Rc<Type>,
items: Vec<AirTree>, items: Vec<AirTree>,
}, },
Pair {
tipo: Rc<Type>,
fst: Box<AirTree>,
snd: Box<AirTree>,
},
Void, Void,
Var { Var {
constructor: ValueConstructor, constructor: ValueConstructor,
@ -320,6 +342,16 @@ pub enum AirTree {
otherwise: Box<AirTree>, otherwise: Box<AirTree>,
}, },
PairClause {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
complex_clause: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
Finally { Finally {
pattern: Box<AirTree>, pattern: Box<AirTree>,
then: Box<AirTree>, then: Box<AirTree>,
@ -363,20 +395,25 @@ impl AirTree {
value: value.to_string(), value: value.to_string(),
} }
} }
pub fn string(value: impl ToString) -> AirTree { pub fn string(value: impl ToString) -> AirTree {
AirTree::String { AirTree::String {
value: value.to_string(), value: value.to_string(),
} }
} }
pub fn byte_array(bytes: Vec<u8>) -> AirTree { pub fn byte_array(bytes: Vec<u8>) -> AirTree {
AirTree::ByteArray { bytes } AirTree::ByteArray { bytes }
} }
pub fn curve(point: Curve) -> AirTree { pub fn curve(point: Curve) -> AirTree {
AirTree::CurvePoint { point } AirTree::CurvePoint { point }
} }
pub fn bool(value: bool) -> AirTree { pub fn bool(value: bool) -> AirTree {
AirTree::Bool { value } AirTree::Bool { value }
} }
pub fn list(mut items: Vec<AirTree>, tipo: Rc<Type>, tail: Option<AirTree>) -> AirTree { pub fn list(mut items: Vec<AirTree>, tipo: Rc<Type>, tail: Option<AirTree>) -> AirTree {
if let Some(tail) = tail { if let Some(tail) = tail {
items.push(tail); items.push(tail);
@ -394,12 +431,23 @@ impl AirTree {
} }
} }
} }
pub fn tuple(items: Vec<AirTree>, tipo: Rc<Type>) -> AirTree { pub fn tuple(items: Vec<AirTree>, tipo: Rc<Type>) -> AirTree {
AirTree::Tuple { tipo, items } AirTree::Tuple { tipo, items }
} }
pub fn pair(fst: AirTree, snd: AirTree, tipo: Rc<Type>) -> AirTree {
AirTree::Pair {
tipo,
fst: fst.into(),
snd: snd.into(),
}
}
pub fn void() -> AirTree { pub fn void() -> AirTree {
AirTree::Void AirTree::Void
} }
pub fn var( pub fn var(
constructor: ValueConstructor, constructor: ValueConstructor,
name: impl ToString, name: impl ToString,
@ -411,6 +459,7 @@ impl AirTree {
variant_name: variant_name.to_string(), variant_name: variant_name.to_string(),
} }
} }
pub fn local_var(name: impl ToString, tipo: Rc<Type>) -> AirTree { pub fn local_var(name: impl ToString, tipo: Rc<Type>) -> AirTree {
AirTree::Var { AirTree::Var {
constructor: ValueConstructor::public( constructor: ValueConstructor::public(
@ -423,6 +472,7 @@ impl AirTree {
variant_name: "".to_string(), variant_name: "".to_string(),
} }
} }
pub fn call(func: AirTree, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree { pub fn call(func: AirTree, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Call { AirTree::Call {
tipo, tipo,
@ -453,6 +503,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn define_cyclic_func( pub fn define_cyclic_func(
func_name: impl ToString, func_name: impl ToString,
module_name: impl ToString, module_name: impl ToString,
@ -468,15 +519,18 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn anon_func(params: Vec<String>, func_body: AirTree) -> AirTree { pub fn anon_func(params: Vec<String>, func_body: AirTree) -> AirTree {
AirTree::Fn { AirTree::Fn {
params, params,
func_body: func_body.into(), func_body: func_body.into(),
} }
} }
pub fn builtin(func: DefaultFunction, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree { pub fn builtin(func: DefaultFunction, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Builtin { func, tipo, args } AirTree::Builtin { func, tipo, args }
} }
pub fn binop( pub fn binop(
op: BinOp, op: BinOp,
tipo: Rc<Type>, tipo: Rc<Type>,
@ -492,12 +546,14 @@ impl AirTree {
argument_tipo, argument_tipo,
} }
} }
pub fn unop(op: UnOp, arg: AirTree) -> AirTree { pub fn unop(op: UnOp, arg: AirTree) -> AirTree {
AirTree::UnOp { AirTree::UnOp {
op, op,
arg: arg.into(), arg: arg.into(),
} }
} }
pub fn let_assignment(name: impl ToString, value: AirTree, then: AirTree) -> AirTree { pub fn let_assignment(name: impl ToString, value: AirTree, then: AirTree) -> AirTree {
AirTree::Let { AirTree::Let {
name: name.to_string(), name: name.to_string(),
@ -505,6 +561,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, msg: Option<AirMsg>) -> AirTree { pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, msg: Option<AirMsg>) -> AirTree {
AirTree::CastFromData { AirTree::CastFromData {
tipo, tipo,
@ -512,12 +569,14 @@ impl AirTree {
msg, msg,
} }
} }
pub fn cast_to_data(value: AirTree, tipo: Rc<Type>) -> AirTree { pub fn cast_to_data(value: AirTree, tipo: Rc<Type>) -> AirTree {
AirTree::CastToData { AirTree::CastToData {
tipo, tipo,
value: value.into(), value: value.into(),
} }
} }
pub fn assert_constr_index( pub fn assert_constr_index(
constr_index: usize, constr_index: usize,
constr: AirTree, constr: AirTree,
@ -531,6 +590,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn assert_bool( pub fn assert_bool(
is_true: bool, is_true: bool,
value: AirTree, value: AirTree,
@ -544,6 +604,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn when( pub fn when(
subject_name: impl ToString, subject_name: impl ToString,
tipo: Rc<Type>, tipo: Rc<Type>,
@ -559,6 +620,7 @@ impl AirTree {
clauses: clauses.into(), clauses: clauses.into(),
} }
} }
pub fn clause( pub fn clause(
subject_name: impl ToString, subject_name: impl ToString,
pattern: AirTree, pattern: AirTree,
@ -576,6 +638,7 @@ impl AirTree {
otherwise: otherwise.into(), otherwise: otherwise.into(),
} }
} }
pub fn list_clause( pub fn list_clause(
tail_name: impl ToString, tail_name: impl ToString,
subject_tipo: Rc<Type>, subject_tipo: Rc<Type>,
@ -593,6 +656,7 @@ impl AirTree {
otherwise: otherwise.into(), otherwise: otherwise.into(),
} }
} }
pub fn tuple_clause( pub fn tuple_clause(
subject_name: impl ToString, subject_name: impl ToString,
subject_tipo: Rc<Type>, subject_tipo: Rc<Type>,
@ -612,12 +676,34 @@ impl AirTree {
otherwise: otherwise.into(), otherwise: otherwise.into(),
} }
} }
pub fn pair_clause(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
fst_name: Option<String>,
snd_name: Option<String>,
then: AirTree,
otherwise: AirTree,
complex_clause: bool,
) -> AirTree {
AirTree::PairClause {
subject_tipo,
subject_name: subject_name.to_string(),
fst_name,
snd_name,
complex_clause,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree { pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree {
AirTree::WrapClause { AirTree::WrapClause {
then: then.into(), then: then.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
} }
} }
pub fn clause_guard( pub fn clause_guard(
subject_name: impl ToString, subject_name: impl ToString,
pattern: AirTree, pattern: AirTree,
@ -631,6 +717,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn list_clause_guard( pub fn list_clause_guard(
tail_name: impl ToString, tail_name: impl ToString,
subject_tipo: Rc<Type>, subject_tipo: Rc<Type>,
@ -646,6 +733,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn tuple_clause_guard( pub fn tuple_clause_guard(
subject_name: impl ToString, subject_name: impl ToString,
subject_tipo: Rc<Type>, subject_tipo: Rc<Type>,
@ -659,12 +747,30 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn pair_clause_guard(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
fst_name: Option<String>,
snd_name: Option<String>,
then: AirTree,
) -> AirTree {
AirTree::PairGuard {
subject_name: subject_name.to_string(),
subject_tipo,
fst_name,
snd_name,
then: then.into(),
}
}
pub fn finally(pattern: AirTree, then: AirTree) -> AirTree { pub fn finally(pattern: AirTree, then: AirTree) -> AirTree {
AirTree::Finally { AirTree::Finally {
pattern: pattern.into(), pattern: pattern.into(),
then: then.into(), then: then.into(),
} }
} }
pub fn if_branches( pub fn if_branches(
mut branches: Vec<(AirTree, AirTree)>, mut branches: Vec<(AirTree, AirTree)>,
tipo: Rc<Type>, tipo: Rc<Type>,
@ -691,6 +797,7 @@ impl AirTree {
final_if final_if
} }
pub fn create_constr(tag: usize, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree { pub fn create_constr(tag: usize, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Constr { tag, tipo, args } AirTree::Constr { tag, tipo, args }
} }
@ -710,6 +817,7 @@ impl AirTree {
args, args,
} }
} }
pub fn index_access(function_name: String, tipo: Rc<Type>, list_of_fields: AirTree) -> AirTree { pub fn index_access(function_name: String, tipo: Rc<Type>, list_of_fields: AirTree) -> AirTree {
AirTree::cast_from_data( AirTree::cast_from_data(
AirTree::call( AirTree::call(
@ -740,6 +848,7 @@ impl AirTree {
None, None,
) )
} }
pub fn fields_expose( pub fn fields_expose(
indices: Vec<(usize, String, Rc<Type>)>, indices: Vec<(usize, String, Rc<Type>)>,
record: AirTree, record: AirTree,
@ -775,6 +884,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn list_expose( pub fn list_expose(
tail_head_names: Vec<(String, String)>, tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>, tail: Option<(String, String)>,
@ -788,6 +898,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn tuple_access( pub fn tuple_access(
names: Vec<String>, names: Vec<String>,
tipo: Rc<Type>, tipo: Rc<Type>,
@ -805,6 +916,27 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn pair_access(
fst: Option<String>,
snd: Option<String>,
tipo: Rc<Type>,
pair: AirTree,
msg: Option<AirMsg>,
is_expect: bool,
then: AirTree,
) -> AirTree {
AirTree::PairAccessor {
fst,
snd,
tipo,
is_expect,
msg,
pair: pair.into(),
then: then.into(),
}
}
pub fn pair_index(index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree { pub fn pair_index(index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree {
AirTree::cast_from_data( AirTree::cast_from_data(
AirTree::builtin( AirTree::builtin(
@ -820,9 +952,11 @@ impl AirTree {
None, None,
) )
} }
pub fn error(tipo: Rc<Type>, validator: bool) -> AirTree { pub fn error(tipo: Rc<Type>, validator: bool) -> AirTree {
AirTree::ErrorTerm { tipo, validator } AirTree::ErrorTerm { tipo, validator }
} }
pub fn trace(msg: AirTree, tipo: Rc<Type>, then: AirTree) -> AirTree { pub fn trace(msg: AirTree, tipo: Rc<Type>, then: AirTree) -> AirTree {
AirTree::Trace { AirTree::Trace {
tipo, tipo,
@ -840,6 +974,7 @@ impl AirTree {
pub fn no_op(then: AirTree) -> AirTree { pub fn no_op(then: AirTree) -> AirTree {
AirTree::NoOp { then: then.into() } AirTree::NoOp { then: then.into() }
} }
pub fn fields_empty(constr: AirTree, msg: Option<AirMsg>, then: AirTree) -> AirTree { pub fn fields_empty(constr: AirTree, msg: Option<AirMsg>, then: AirTree) -> AirTree {
AirTree::FieldsEmpty { AirTree::FieldsEmpty {
constr: constr.into(), constr: constr.into(),
@ -847,6 +982,7 @@ impl AirTree {
then: then.into(), then: then.into(),
} }
} }
pub fn list_empty(list: AirTree, msg: Option<AirMsg>, then: AirTree) -> AirTree { pub fn list_empty(list: AirTree, msg: Option<AirMsg>, then: AirTree) -> AirTree {
AirTree::ListEmpty { AirTree::ListEmpty {
list: list.into(), list: list.into(),
@ -1058,6 +1194,21 @@ impl AirTree {
}); });
then.create_air_vec(air_vec); then.create_air_vec(air_vec);
} }
AirTree::PairGuard {
subject_tipo,
subject_name,
fst_name,
snd_name,
then,
} => {
air_vec.push(Air::PairGuard {
subject_tipo: subject_tipo.clone(),
subject_name: subject_name.clone(),
fst_name: fst_name.clone(),
snd_name: snd_name.clone(),
});
then.create_air_vec(air_vec);
}
AirTree::FieldsExpose { AirTree::FieldsExpose {
indices, indices,
record, record,
@ -1134,6 +1285,29 @@ impl AirTree {
tuple.create_air_vec(air_vec); tuple.create_air_vec(air_vec);
then.create_air_vec(air_vec); then.create_air_vec(air_vec);
} }
AirTree::PairAccessor {
fst,
snd,
tipo,
is_expect,
msg,
pair,
then,
} => {
air_vec.push(Air::PairAccessor {
fst: fst.clone(),
snd: snd.clone(),
tipo: tipo.clone(),
is_expect: *is_expect,
});
if let Some(msg) = msg {
msg.to_air_tree().create_air_vec(air_vec);
}
pair.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::FieldsEmpty { constr, msg, then } => { AirTree::FieldsEmpty { constr, msg, then } => {
air_vec.push(Air::FieldsEmpty); air_vec.push(Air::FieldsEmpty);
@ -1189,6 +1363,11 @@ impl AirTree {
item.create_air_vec(air_vec); item.create_air_vec(air_vec);
} }
} }
AirTree::Pair { tipo, fst, snd } => {
air_vec.push(Air::Pair { tipo: tipo.clone() });
fst.create_air_vec(air_vec);
snd.create_air_vec(air_vec);
}
AirTree::Void => air_vec.push(Air::Void), AirTree::Void => air_vec.push(Air::Void),
AirTree::Var { AirTree::Var {
constructor, constructor,
@ -1334,6 +1513,25 @@ impl AirTree {
then.create_air_vec(air_vec); then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec); otherwise.create_air_vec(air_vec);
} }
AirTree::PairClause {
subject_tipo,
subject_name,
fst_name,
snd_name,
complex_clause,
then,
otherwise,
} => {
air_vec.push(Air::PairClause {
subject_tipo: subject_tipo.clone(),
subject_name: subject_name.clone(),
fst_name: fst_name.clone(),
snd_name: snd_name.clone(),
complex_clause: *complex_clause,
});
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::Finally { pattern, then } => { AirTree::Finally { pattern, then } => {
air_vec.push(Air::Finally); air_vec.push(Air::Finally);
pattern.create_air_vec(air_vec); pattern.create_air_vec(air_vec);
@ -1398,6 +1596,7 @@ impl AirTree {
AirTree::CurvePoint { point } => point.tipo(), AirTree::CurvePoint { point } => point.tipo(),
AirTree::List { tipo, .. } AirTree::List { tipo, .. }
| AirTree::Tuple { tipo, .. } | AirTree::Tuple { tipo, .. }
| AirTree::Pair { tipo, .. }
| AirTree::Call { tipo, .. } | AirTree::Call { tipo, .. }
| AirTree::Builtin { tipo, .. } | AirTree::Builtin { tipo, .. }
| AirTree::BinOp { tipo, .. } | AirTree::BinOp { tipo, .. }
@ -1420,6 +1619,7 @@ impl AirTree {
| AirTree::ListClause { then, .. } | AirTree::ListClause { then, .. }
| AirTree::WrapClause { then, .. } | AirTree::WrapClause { then, .. }
| AirTree::TupleClause { then, .. } | AirTree::TupleClause { then, .. }
| AirTree::PairClause { then, .. }
| AirTree::Finally { then, .. } | AirTree::Finally { then, .. }
| AirTree::Let { then, .. } | AirTree::Let { then, .. }
| AirTree::DefineFunc { then, .. } | AirTree::DefineFunc { then, .. }
@ -1429,10 +1629,12 @@ impl AirTree {
| AirTree::ClauseGuard { then, .. } | AirTree::ClauseGuard { then, .. }
| AirTree::ListClauseGuard { then, .. } | AirTree::ListClauseGuard { then, .. }
| AirTree::TupleGuard { then, .. } | AirTree::TupleGuard { then, .. }
| AirTree::PairGuard { then, .. }
| AirTree::FieldsExpose { then, .. } | AirTree::FieldsExpose { then, .. }
| AirTree::ListAccessor { then, .. } | AirTree::ListAccessor { then, .. }
| AirTree::ListExpose { then, .. } | AirTree::ListExpose { then, .. }
| AirTree::TupleAccessor { then, .. } | AirTree::TupleAccessor { then, .. }
| AirTree::PairAccessor { then, .. }
| AirTree::FieldsEmpty { then, .. } | AirTree::FieldsEmpty { then, .. }
| AirTree::ListEmpty { then, .. } | AirTree::ListEmpty { then, .. }
| AirTree::NoOp { then } => then.return_type(), | AirTree::NoOp { then } => then.return_type(),
@ -1525,7 +1727,8 @@ impl AirTree {
tree_path.push(current_depth, depth_index); tree_path.push(current_depth, depth_index);
let mut tuple_then_index = None; let mut tuple_then_index = None;
// Assignments/Statements get traversed here // Assignments'/Statements' values get traversed here
// Then the body under these assignments/statements get traversed later on
match self { match self {
AirTree::Let { value, .. } => { AirTree::Let { value, .. } => {
value.do_traverse_tree_with( value.do_traverse_tree_with(
@ -1592,6 +1795,15 @@ impl AirTree {
apply_with_func_last, apply_with_func_last,
); );
} }
AirTree::PairAccessor { pair, .. } => {
pair.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
}
AirTree::FieldsEmpty { constr, .. } => { AirTree::FieldsEmpty { constr, .. } => {
constr.do_traverse_tree_with( constr.do_traverse_tree_with(
tree_path, tree_path,
@ -1629,7 +1841,49 @@ impl AirTree {
apply_with_func_last, apply_with_func_last,
); );
} }
_ => {} AirTree::PairClause { otherwise, .. } => {
tuple_then_index = Some(index_count.next_number());
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
}
AirTree::DefineFunc { .. }
| AirTree::DefineCyclicFuncs { .. }
| AirTree::ListClauseGuard { .. }
| AirTree::TupleGuard { .. }
| AirTree::PairGuard { .. }
| AirTree::ListExpose { .. }
| AirTree::NoOp { .. }
| AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::List { .. }
| AirTree::Tuple { .. }
| AirTree::Pair { .. }
| AirTree::Void
| AirTree::Var { .. }
| AirTree::Call { .. }
| AirTree::Fn { .. }
| AirTree::Builtin { .. }
| AirTree::BinOp { .. }
| AirTree::UnOp { .. }
| AirTree::CastFromData { .. }
| AirTree::CastToData { .. }
| AirTree::Clause { .. }
| AirTree::ListClause { .. }
| AirTree::WrapClause { .. }
| AirTree::Finally { .. }
| AirTree::If { .. }
| AirTree::Constr { .. }
| AirTree::RecordUpdate { .. }
| AirTree::ErrorTerm { .. }
| AirTree::Trace { .. } => {}
} }
if !apply_with_func_last { if !apply_with_func_last {
@ -1645,11 +1899,13 @@ impl AirTree {
| AirTree::FieldsExpose { then, .. } | AirTree::FieldsExpose { then, .. }
| AirTree::ListAccessor { then, .. } | AirTree::ListAccessor { then, .. }
| AirTree::TupleAccessor { then, .. } | AirTree::TupleAccessor { then, .. }
| AirTree::PairAccessor { then, .. }
| AirTree::FieldsEmpty { then, .. } | AirTree::FieldsEmpty { then, .. }
| AirTree::ListEmpty { then, .. } | AirTree::ListEmpty { then, .. }
| AirTree::ListExpose { then, .. } | AirTree::ListExpose { then, .. }
| AirTree::ListClauseGuard { then, .. } | AirTree::ListClauseGuard { then, .. }
| AirTree::TupleGuard { then, .. } | AirTree::TupleGuard { then, .. }
| AirTree::PairGuard { then, .. }
| AirTree::NoOp { then } => { | AirTree::NoOp { then } => {
then.do_traverse_tree_with( then.do_traverse_tree_with(
tree_path, tree_path,
@ -1681,6 +1937,19 @@ impl AirTree {
apply_with_func_last, apply_with_func_last,
); );
} }
AirTree::PairClause { then, .. } => {
let Some(index) = tuple_then_index else {
unreachable!()
};
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
index,
with,
apply_with_func_last,
);
}
AirTree::List { items, .. } => { AirTree::List { items, .. } => {
for item in items { for item in items {
item.do_traverse_tree_with( item.do_traverse_tree_with(
@ -1703,6 +1972,23 @@ impl AirTree {
); );
} }
} }
AirTree::Pair { fst, snd, .. } => {
fst.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
snd.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
}
AirTree::Call { func, args, .. } => { AirTree::Call { func, args, .. } => {
func.do_traverse_tree_with( func.do_traverse_tree_with(
tree_path, tree_path,
@ -2071,6 +2357,13 @@ impl AirTree {
panic!("Tree Path index outside tree children nodes") panic!("Tree Path index outside tree children nodes")
} }
} }
AirTree::PairGuard { then, .. } => {
if *index == 0 {
then.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirTree::FieldsExpose { record, then, .. } => { AirTree::FieldsExpose { record, then, .. } => {
if *index == 0 { if *index == 0 {
record.as_mut().do_find_air_tree_node(tree_path_iter) record.as_mut().do_find_air_tree_node(tree_path_iter)
@ -2105,6 +2398,15 @@ impl AirTree {
panic!("Tree Path index outside tree children nodes") panic!("Tree Path index outside tree children nodes")
} }
} }
AirTree::PairAccessor { pair, then, .. } => {
if *index == 0 {
pair.as_mut().do_find_air_tree_node(tree_path_iter)
} else if *index == 1 {
then.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirTree::NoOp { then } => { AirTree::NoOp { then } => {
if *index == 0 { if *index == 0 {
then.as_mut().do_find_air_tree_node(tree_path_iter) then.as_mut().do_find_air_tree_node(tree_path_iter)
@ -2112,8 +2414,7 @@ impl AirTree {
panic!("Tree Path index outside tree children nodes") panic!("Tree Path index outside tree children nodes")
} }
} }
AirTree::DefineFunc { .. } => unreachable!(), AirTree::DefineFunc { .. } | AirTree::DefineCyclicFuncs { .. } => unreachable!(),
AirTree::DefineCyclicFuncs { .. } => unreachable!(),
AirTree::FieldsEmpty { constr, then, .. } => { AirTree::FieldsEmpty { constr, then, .. } => {
if *index == 0 { if *index == 0 {
constr.as_mut().do_find_air_tree_node(tree_path_iter) constr.as_mut().do_find_air_tree_node(tree_path_iter)
@ -2140,6 +2441,15 @@ impl AirTree {
.expect("Tree Path index outside tree children nodes"); .expect("Tree Path index outside tree children nodes");
item.do_find_air_tree_node(tree_path_iter) item.do_find_air_tree_node(tree_path_iter)
} }
AirTree::Pair { fst, snd, .. } => {
if *index == 0 {
fst.as_mut().do_find_air_tree_node(tree_path_iter)
} else if *index == 1 {
snd.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirTree::Call { func, args, .. } => { AirTree::Call { func, args, .. } => {
children_nodes.push(func.as_mut()); children_nodes.push(func.as_mut());
children_nodes.extend(args.iter_mut()); children_nodes.extend(args.iter_mut());
@ -2243,6 +2553,17 @@ impl AirTree {
panic!("Tree Path index outside tree children nodes") panic!("Tree Path index outside tree children nodes")
} }
} }
AirTree::PairClause {
then, otherwise, ..
} => {
if *index == 0 {
then.as_mut().do_find_air_tree_node(tree_path_iter)
} else if *index == 1 {
otherwise.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirTree::Finally { pattern, then } => { AirTree::Finally { pattern, then } => {
if *index == 0 { if *index == 0 {
pattern.as_mut().do_find_air_tree_node(tree_path_iter) pattern.as_mut().do_find_air_tree_node(tree_path_iter)
@ -2291,7 +2612,15 @@ impl AirTree {
panic!("Tree Path index outside tree children nodes") panic!("Tree Path index outside tree children nodes")
} }
} }
_ => {
AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::Void
| AirTree::Var { .. }
| AirTree::ErrorTerm { .. } => {
panic!("A tree node with no children was encountered with a longer tree path.") panic!("A tree node with no children was encountered with a longer tree path.")
} }
} }

View File

@ -453,6 +453,12 @@ impl Type {
Self::Var { tipo, .. } => tipo.borrow().get_inner_types(), Self::Var { tipo, .. } => tipo.borrow().get_inner_types(),
_ => vec![], _ => vec![],
} }
} else if self.is_pair() {
match self {
Self::Pair { fst, snd, .. } => vec![fst.clone(), snd.clone()],
Self::Var { tipo, .. } => tipo.borrow().get_inner_types(),
_ => vec![],
}
} else if matches!(self.get_uplc_type(), UplcType::Data) { } else if matches!(self.get_uplc_type(), UplcType::Data) {
match self { match self {
Type::App { args, .. } => args.clone(), Type::App { args, .. } => args.clone(),