feat: finished when constr is for IR and code gen

This commit is contained in:
Kasey White 2022-11-28 02:49:39 -05:00 committed by Lucas
parent 3fb3a3240a
commit 29a30aa61f
4 changed files with 369 additions and 56 deletions

View File

@ -141,7 +141,7 @@ pub enum IR {
FieldsExpose {
count: usize,
indices: Vec<usize>,
indices: Vec<(usize, String, Arc<Type>)>,
},
// ModuleSelect {

View File

@ -1,9 +1,9 @@
use std::{collections::HashMap, ops::Deref, sync::Arc};
use std::{collections::HashMap, ops::Deref, sync::Arc, vec};
use itertools::Itertools;
use uplc::{
ast::{
builder::{self, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD},
builder::{self, constr_index_exposer, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD},
Constant, Name, Program, Term,
},
builtins::DefaultFunction,
@ -515,26 +515,35 @@ impl<'a> CodeGenerator<'a> {
tipo,
..
} => {
if *is_record {
let data_type_key = match tipo.as_ref() {
Type::Fn { ret, .. } => match &**ret {
Type::App { module, name, .. } => DataTypeKey {
module_name: module.clone(),
defined_type: name.clone(),
},
_ => unreachable!(),
let data_type_key = match tipo.as_ref() {
Type::Fn { ret, .. } => match &**ret {
Type::App { module, name, .. } => DataTypeKey {
module_name: module.clone(),
defined_type: name.clone(),
},
_ => unreachable!(),
};
},
Type::App { module, name, .. } => DataTypeKey {
module_name: module.clone(),
defined_type: name.clone(),
},
_ => unreachable!(),
};
let data_type = self.data_types.get(&data_type_key).unwrap();
let (index, constructor_type) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, dt)| &dt.name == constr_name)
.unwrap();
let data_type = self.data_types.get(&data_type_key).unwrap();
let (index, constructor_type) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, dt)| &dt.name == constr_name)
.unwrap();
// push constructor Index
pattern_vec.push(IR::Int {
value: index.to_string(),
});
if *is_record {
let field_map = match constructor {
tipo::PatternConstructor::Record { field_map, .. } => {
field_map.clone().unwrap()
@ -569,43 +578,64 @@ impl<'a> CodeGenerator<'a> {
.sorted_by(|item1, item2| item1.2.cmp(&item2.2))
.collect::<Vec<(String, String, usize, bool)>>();
// push constructor Index
pattern_vec.push(IR::Int {
value: index.to_string(),
});
if !arguments_index.is_empty() {
pattern_vec.push(IR::FieldsExpose {
count: arguments_index.len() + 2,
indices: arguments_index
.iter()
.map(|(_, _, index, _)| *index)
.map(|(label, var_name, index, _)| {
let field_type = type_map.get(label).unwrap();
(*index, var_name.clone(), field_type.clone())
})
.collect_vec(),
});
for arg in arguments_index {
let field_label = arg.0;
let field_type = type_map.get(&field_label).unwrap();
let field_var = arg.1;
pattern_vec.push(IR::Var {
constructor: ValueConstructor::public(
field_type.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: field_var,
})
}
}
pattern_vec.append(values);
} else {
println!("todo");
let mut type_map: HashMap<usize, Arc<Type>> = HashMap::new();
for (index, arg) in constructor_type.arguments.iter().enumerate() {
let field_type = arg.tipo.clone();
type_map.insert(index, field_type);
}
let arguments_index = arguments
.iter()
.enumerate()
.map(|(index, item)| {
let (discard, var_name) = match &item.value {
Pattern::Var { name, .. } => (false, name.clone()),
Pattern::Discard { .. } => (true, "".to_string()),
Pattern::List { .. } => todo!(),
Pattern::Constructor { .. } => todo!(),
_ => todo!(),
};
(var_name, index, discard)
})
.filter(|(_, _, discard)| !discard)
.collect::<Vec<(String, usize, bool)>>();
if !arguments_index.is_empty() {
pattern_vec.push(IR::FieldsExpose {
count: arguments_index.len() + 2,
indices: arguments_index
.iter()
.map(|(name, index, _)| {
let field_type = type_map.get(index).unwrap();
(*index, name.clone(), field_type.clone())
})
.collect_vec(),
});
}
}
pattern_vec.append(values);
}
}
}
fn uplc_code_gen(&self, ir_stack: &mut Vec<IR>) -> Term<Name> {
fn uplc_code_gen(&mut self, ir_stack: &mut Vec<IR>) -> Term<Name> {
let mut arg_stack: Vec<Term<Name>> = vec![];
while let Some(ir_element) = ir_stack.pop() {
@ -615,7 +645,7 @@ impl<'a> CodeGenerator<'a> {
arg_stack[0].clone()
}
fn gen_uplc(&self, ir: IR, arg_stack: &mut Vec<Term<Name>>) {
fn gen_uplc(&mut self, ir: IR, arg_stack: &mut Vec<Term<Name>>) {
match ir {
IR::Int { value } => {
let integer = value.parse().unwrap();
@ -924,7 +954,14 @@ impl<'a> CodeGenerator<'a> {
}
}
BinOp::NotEq => todo!(),
BinOp::LtInt => todo!(),
BinOp::LtInt => Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::LessThanInteger).into(),
argument: left.into(),
}
.into(),
argument: right.into(),
},
BinOp::LtEqInt => todo!(),
BinOp::GtEqInt => todo!(),
BinOp::GtInt => Term::Apply {
@ -976,7 +1013,24 @@ impl<'a> CodeGenerator<'a> {
IR::DefineConst { .. } => todo!(),
IR::DefineConstrFields { .. } => todo!(),
IR::DefineConstrFieldAccess { .. } => todo!(),
IR::Lam { .. } => todo!(),
IR::Lam { name } => {
let arg = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: arg.into(),
};
arg_stack.push(term);
}
IR::When {
subject_name, tipo, ..
} => {
@ -984,7 +1038,8 @@ impl<'a> CodeGenerator<'a> {
let mut term = arg_stack.pop().unwrap();
term = if tipo.is_int() {
term = if tipo.is_int() || tipo.is_bytearray() || tipo.is_string() || tipo.is_list()
{
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
@ -997,7 +1052,17 @@ impl<'a> CodeGenerator<'a> {
argument: subject.into(),
}
} else {
todo!()
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: subject_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: constr_index_exposer(subject).into(),
}
};
arg_stack.push(term);
@ -1077,12 +1142,7 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
IR::Finally => {
let clause = arg_stack.pop().unwrap();
if !clause.is_unit() {
let _body = arg_stack.pop().unwrap();
todo!();
}
let _clause = arg_stack.pop().unwrap();
}
IR::If { .. } => todo!(),
IR::Constr { .. } => todo!(),
@ -1130,7 +1190,247 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
IR::FieldsExpose { .. } => todo!(),
IR::FieldsExpose {
count: _count,
indices,
} => {
self.needs_field_access = true;
let constr_var = arg_stack.pop().unwrap();
let mut body = arg_stack.pop().unwrap();
let mut indices = indices.into_iter().rev();
let highest = indices.next().unwrap();
let mut id_list = vec![];
for _ in 0..highest.0 {
id_list.push(self.id_gen.next());
}
let constr_name_lam = format!("__constr_fields_{}", self.id_gen.next());
let highest_loop_index = highest.0 as i32 - 1;
let last_prev_tail = Term::Var(Name {
text: if highest_loop_index == -1 {
constr_name_lam.clone()
} else {
format!(
"__tail_{}_{}",
highest_loop_index, id_list[highest_loop_index as usize]
)
},
unique: 0.into(),
});
let unwrapper = if highest.2.is_int() {
Term::Apply {
function: DefaultFunction::UnIData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else if highest.2.is_bytearray() {
Term::Apply {
function: DefaultFunction::UnBData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else if highest.2.is_list() {
Term::Apply {
function: DefaultFunction::UnListData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else {
Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
};
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: highest.1,
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: unwrapper.into(),
};
let mut current_field = None;
for index in (0..highest.0).rev() {
let current_tail_index = index;
let previous_tail_index = if index == 0 { 0 } else { index - 1 };
let current_tail_id = id_list[index];
let previous_tail_id = if index == 0 { 0 } else { id_list[index - 1] };
if current_field.is_none() {
current_field = indices.next();
}
let prev_tail = if index == 0 {
Term::Var(Name {
text: constr_name_lam.clone(),
unique: 0.into(),
})
} else {
Term::Var(Name {
text: format!("__tail_{previous_tail_index}_{previous_tail_id}"),
unique: 0.into(),
})
};
if let Some(ref field) = current_field {
if field.0 == index {
let unwrapper = if field.2.is_int() {
Term::Apply {
function: DefaultFunction::UnIData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else if field.2.is_bytearray() {
Term::Apply {
function: DefaultFunction::UnBData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else if field.2.is_list() {
Term::Apply {
function: DefaultFunction::UnListData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else {
Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
};
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: field.1.clone(),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!(
"__tail_{current_tail_index}_{current_tail_id}"
),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
.into(),
}
.into(),
argument: unwrapper.into(),
};
current_field = None;
} else {
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!(
"__tail_{current_tail_index}_{current_tail_id}"
),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
}
} else {
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!("__tail_{current_tail_index}_{current_tail_id}"),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
}
}
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: constr_name_lam,
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Var(Name {
text: CONSTR_FIELDS_EXPOSER.to_string(),
unique: 0.into(),
})
.into(),
argument: constr_var.into(),
}
.into(),
};
arg_stack.push(body);
}
IR::Todo { .. } => todo!(),
IR::RecordUpdate { .. } => todo!(),
IR::Negate { .. } => todo!(),

View File

@ -3,6 +3,7 @@ use crate::builtins::DefaultFunction;
use super::{Constant, Name, Term};
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
pub fn final_wrapper<T>(term: Term<T>) -> Term<T> {
@ -59,6 +60,18 @@ pub fn constr_fields_exposer(term: Term<Name>) -> Term<Name> {
}
}
pub fn constr_index_exposer(term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Force(Term::Force(Term::Builtin(DefaultFunction::FstPair).into()).into())
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::UnConstrData).into(),
argument: term.into(),
}
.into(),
}
}
pub fn constr_get_field(term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Lambda {

View File

@ -44,14 +44,14 @@ pub fn who(a: ByteArray) -> ByteArray {
}
pub type Datum {
Offer { price: Int, asset_class: ByteArray }
Offer { price: Int, asset_class: ByteArray, thing: Int }
Sell
Hold(Int)
}
pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool {
when datum is {
Offer { price, .. } -> price > 0
Offer { price, thing: t, .. } -> price > 0
Hold(less) -> less < 0
Sell -> False
}