diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 9e8882f4..87d33175 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -5371,6 +5371,11 @@ impl<'a> CodeGenerator<'a> { )) } } + Air::ExtractField { tipo } => { + let arg = arg_stack.pop().unwrap(); + + Some(known_data_to_type(Term::head_list().apply(arg), &tipo)) + } } } } diff --git a/crates/aiken-lang/src/gen_uplc/air.rs b/crates/aiken-lang/src/gen_uplc/air.rs index cd6d98be..56a5826e 100644 --- a/crates/aiken-lang/src/gen_uplc/air.rs +++ b/crates/aiken-lang/src/gen_uplc/air.rs @@ -211,13 +211,16 @@ pub enum Air { tipo: Rc, is_expect: bool, }, - // Tuple Access + // Pair Access PairAccessor { fst: Option, snd: Option, tipo: Rc, is_expect: bool, }, + ExtractField { + tipo: Rc, + }, // Misc. ErrorTerm { tipo: Rc, diff --git a/crates/aiken-lang/src/gen_uplc/decision_tree.rs b/crates/aiken-lang/src/gen_uplc/decision_tree.rs index 95dcfcec..96b9951f 100644 --- a/crates/aiken-lang/src/gen_uplc/decision_tree.rs +++ b/crates/aiken-lang/src/gen_uplc/decision_tree.rs @@ -27,6 +27,7 @@ pub enum Path { Pair(usize), Tuple(usize), Constr(Rc, usize), + OpaqueConstr(Rc), List(usize), ListTail(usize), } @@ -43,6 +44,7 @@ impl ToString for Path { Path::Constr(_, i) => { format!("constr_{}", i) } + Path::OpaqueConstr(_) => "opaqueconstr".to_string(), Path::List(i) => { format!("list_{}", i) } @@ -61,6 +63,7 @@ impl PartialEq for Path { | (Path::Constr(_, a), Path::Constr(_, b)) | (Path::List(a), Path::List(b)) | (Path::ListTail(a), Path::ListTail(b)) => a == b, + (Path::OpaqueConstr(_), Path::OpaqueConstr(_)) => true, _ => false, } } @@ -1094,6 +1097,9 @@ impl<'a, 'b> TreeGen<'a, 'b> { } => { let data_type = lookup_data_type_by_tipo(self.data_types, ¤t_tipo).unwrap(); + let is_transparent = + data_type.opaque && data_type.constructors[0].arguments.len() == 1; + if data_type.constructors.len() == 1 || data_type.is_never() { arguments .iter() @@ -1103,7 +1109,11 @@ impl<'a, 'b> TreeGen<'a, 'b> { let mut item_path = path.clone(); - item_path.push(Path::Constr(tipo.clone(), index)); + if is_transparent { + item_path.push(Path::OpaqueConstr(tipo.clone())); + } else { + item_path.push(Path::Constr(tipo.clone(), index)); + } let (assigns, patts) = self.map_pattern_to_row(arg_value, subject_tipo, item_path); @@ -1199,6 +1209,10 @@ pub fn get_tipo_by_path(mut subject_tipo: Rc, mut path: &[Path]) -> Rc subject_tipo.get_inner_types().swap_remove(0), Path::ListTail(_) => subject_tipo, Path::Constr(tipo, index) => tipo.arg_types().unwrap().swap_remove(*index), + Path::OpaqueConstr(tipo) => { + let x = tipo.arg_types().unwrap().swap_remove(0); + x + } }; path = rest diff --git a/crates/aiken-lang/src/gen_uplc/stick_break_set.rs b/crates/aiken-lang/src/gen_uplc/stick_break_set.rs index 27eadd41..d4c9f0f2 100644 --- a/crates/aiken-lang/src/gen_uplc/stick_break_set.rs +++ b/crates/aiken-lang/src/gen_uplc/stick_break_set.rs @@ -14,6 +14,7 @@ use super::{ #[derive(Clone, Debug)] pub enum Builtin { HeadList(Rc), + ExtractField(Rc), TailList, UnConstrFields, FstPair(Rc), @@ -24,6 +25,7 @@ impl PartialEq for Builtin { fn eq(&self, other: &Self) -> bool { match (self, other) { (Builtin::HeadList(_), Builtin::HeadList(_)) + | (Builtin::ExtractField(_), Builtin::ExtractField(_)) | (Builtin::TailList, Builtin::TailList) | (Builtin::UnConstrFields, Builtin::UnConstrFields) | (Builtin::FstPair(_), Builtin::FstPair(_)) @@ -39,6 +41,7 @@ impl Builtin { fn to_air_call(self, special_funcs: &mut CodeGenSpecialFuncs, arg: AirTree) -> AirTree { match self { Builtin::HeadList(t) => AirTree::builtin(DefaultFunction::HeadList, t, vec![arg]), + Builtin::ExtractField(t) => AirTree::extract_field(t, arg), Builtin::TailList => AirTree::builtin( DefaultFunction::TailList, Type::list(Type::data()), @@ -58,10 +61,9 @@ impl Builtin { pub fn tipo(&self) -> Rc { match self { Builtin::HeadList(t) => t.clone(), + Builtin::ExtractField(t) => t.clone(), Builtin::TailList => Type::list(Type::data()), - Builtin::UnConstrFields => Type::list(Type::data()), - Builtin::FstPair(t) => t.clone(), Builtin::SndPair(t) => t.clone(), } @@ -72,6 +74,7 @@ impl ToString for Builtin { fn to_string(&self) -> String { match self { Builtin::HeadList(_) => "head".to_string(), + Builtin::ExtractField(_) => "extractfield".to_string(), Builtin::TailList => "tail".to_string(), Builtin::UnConstrFields => "unconstrfields".to_string(), Builtin::FstPair(_) => "fst".to_string(), @@ -110,6 +113,8 @@ impl Builtins { .into_iter() .fold((vec![], vec![]), |(mut builtins, mut rebuilt_path), i| { rebuilt_path.push(i.clone()); + let is_list = matches!(i, Path::List(_)); + match i { Path::Pair(i) => { if i == 0 { @@ -133,10 +138,17 @@ impl Builtins { builtins.push(Builtin::TailList); } - builtins.push(Builtin::HeadList(get_tipo_by_path( - subject_tipo.clone(), - &rebuilt_path, - ))); + if is_list { + builtins.push(Builtin::HeadList(get_tipo_by_path( + subject_tipo.clone(), + &rebuilt_path, + ))); + } else { + builtins.push(Builtin::ExtractField(get_tipo_by_path( + subject_tipo.clone(), + &rebuilt_path, + ))); + } (builtins, rebuilt_path) } @@ -147,7 +159,7 @@ impl Builtins { builtins.push(Builtin::TailList); } - builtins.push(Builtin::HeadList(get_tipo_by_path( + builtins.push(Builtin::ExtractField(get_tipo_by_path( subject_tipo.clone(), &rebuilt_path, ))); @@ -162,6 +174,7 @@ impl Builtins { (builtins, rebuilt_path) } + Path::OpaqueConstr(_) => (builtins, rebuilt_path), } }) .0, diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index 0ac2382c..7803c764 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -235,6 +235,10 @@ pub enum AirTree { then: Box, otherwise: Box, }, + ExtractField { + tipo: Rc, + arg: Box, + }, // Misc. FieldsEmpty { constr: Box, @@ -970,6 +974,13 @@ impl AirTree { } } + pub fn extract_field(tipo: Rc, arg: AirTree) -> AirTree { + AirTree::ExtractField { + tipo, + arg: arg.into(), + } + } + pub fn pair_index(index: usize, tipo: Rc, tuple: AirTree) -> AirTree { AirTree::cast_from_data( AirTree::builtin( @@ -1651,6 +1662,13 @@ impl AirTree { msg.create_air_vec(air_vec); then.create_air_vec(air_vec); } + AirTree::ExtractField { + tipo, + arg: args_list, + } => { + air_vec.push(Air::ExtractField { tipo: tipo.clone() }); + args_list.create_air_vec(air_vec); + } } } @@ -1666,6 +1684,7 @@ impl AirTree { | AirTree::Pair { tipo, .. } | AirTree::Call { tipo, .. } | AirTree::Builtin { tipo, .. } + | AirTree::ExtractField { tipo, .. } | AirTree::BinOp { tipo, .. } | AirTree::CastFromData { tipo, .. } | AirTree::When { tipo, .. } @@ -1728,6 +1747,7 @@ impl AirTree { | AirTree::Tuple { tipo, .. } | AirTree::Call { tipo, .. } | AirTree::Builtin { tipo, .. } + | AirTree::ExtractField { tipo, .. } | AirTree::CastFromData { tipo, .. } | AirTree::CastToData { tipo, .. } | AirTree::If { tipo, .. } @@ -2077,7 +2097,8 @@ impl AirTree { | AirTree::Constr { .. } | AirTree::RecordUpdate { .. } | AirTree::ErrorTerm { .. } - | AirTree::Trace { .. } => {} + | AirTree::Trace { .. } + | AirTree::ExtractField { .. } => {} } match self { @@ -2191,6 +2212,9 @@ impl AirTree { ); } } + AirTree::ExtractField { tipo: _, arg } => { + arg.do_traverse_tree_with(tree_path, current_depth + 1, Fields::SecondField, with); + } AirTree::BinOp { name: _, tipo: _, @@ -2735,6 +2759,10 @@ impl AirTree { .do_find_air_tree_node(tree_path_iter), _ => panic!("Tree Path index outside tree children nodes"), }, + AirTree::ExtractField { tipo: _, arg } => match field { + Fields::SecondField => arg.as_mut().do_find_air_tree_node(tree_path_iter), + _ => panic!("Tree Path index outside tree children nodes"), + }, AirTree::Pair { tipo: _, fst, snd } => match field { Fields::SecondField => fst.as_mut().do_find_air_tree_node(tree_path_iter), Fields::ThirdField => snd.as_mut().do_find_air_tree_node(tree_path_iter),