feat: when statements with field access now work

This commit is contained in:
Kasey White 2022-11-16 04:29:50 -05:00 committed by Lucas
parent 8d1e73bbea
commit f10c78d800
3 changed files with 165 additions and 153 deletions

View File

@ -9,7 +9,7 @@ use uplc::{
}; };
use crate::{ use crate::{
ast::{BinOp, DataType, Function, Pattern, Span, TypedArg, TypedPattern}, ast::{AssignmentKind, BinOp, DataType, Function, Pattern, Span, TypedArg, TypedPattern},
expr::TypedExpr, expr::TypedExpr,
tipo::{self, ModuleValueConstructor, Type, ValueConstructorVariant}, tipo::{self, ModuleValueConstructor, Type, ValueConstructorVariant},
}; };
@ -120,12 +120,6 @@ impl<'a> CodeGenerator<'a> {
pub fn generate(&mut self, body: TypedExpr, arguments: Vec<TypedArg>) -> Program<Name> { pub fn generate(&mut self, body: TypedExpr, arguments: Vec<TypedArg>) -> Program<Name> {
self.recurse_scope_level(&body, ScopeLevels::new()); self.recurse_scope_level(&body, ScopeLevels::new());
println!(
"DATA USAGE HOLDER IS {:#?}",
self.uplc_data_usage_holder_lookup
);
println!("DATA HOLDER IS {:#?}", self.uplc_data_holder_lookup);
self.uplc_function_holder_lookup self.uplc_function_holder_lookup
.sort_by(|_key1, value1, _key2, value2| { .sort_by(|_key1, value1, _key2, value2| {
if value1.is_less_than(value2, true) { if value1.is_less_than(value2, true) {
@ -219,7 +213,7 @@ impl<'a> CodeGenerator<'a> {
} }
pub(crate) fn recurse_scope_level(&mut self, body: &TypedExpr, scope_level: ScopeLevels) { pub(crate) fn recurse_scope_level(&mut self, body: &TypedExpr, scope_level: ScopeLevels) {
match dbg!(body) { match body {
TypedExpr::Int { .. } => {} TypedExpr::Int { .. } => {}
TypedExpr::String { .. } => {} TypedExpr::String { .. } => {}
TypedExpr::ByteArray { .. } => {} TypedExpr::ByteArray { .. } => {}
@ -233,52 +227,9 @@ impl<'a> CodeGenerator<'a> {
} }
} }
TypedExpr::Var { TypedExpr::Var { constructor, .. } => {
constructor, name, ..
} => {
match constructor.variant.clone() { match constructor.variant.clone() {
ValueConstructorVariant::LocalVariable { .. } => { ValueConstructorVariant::LocalVariable { .. } => {}
let mut is_done_loop = false;
let mut current_tipo: Type = (*constructor.tipo).clone();
let mut current_module = "".to_string();
while !is_done_loop {
match current_tipo.clone() {
Type::App { module, .. } => {
is_done_loop = true;
current_module = module.clone();
}
Type::Fn { .. } => {
is_done_loop = true;
}
Type::Var { tipo } => {
let x = tipo.borrow().clone();
match x {
tipo::TypeVar::Unbound { .. } => todo!(),
tipo::TypeVar::Link { tipo } => {
current_tipo = (*tipo).clone();
}
tipo::TypeVar::Generic { .. } => todo!(),
}
}
}
}
if let Some(val) = self
.uplc_data_usage_holder_lookup
.get(&(current_module.to_string(), name.clone()))
{
if scope_level.is_less_than(val, false) {
println!(
"DATA USAGE HOLDER CHANGED 1 IS {:#?}",
self.uplc_data_usage_holder_lookup
);
self.uplc_data_usage_holder_lookup
.insert((current_module, name.clone()), scope_level);
}
}
}
ValueConstructorVariant::ModuleConstant { .. } => todo!(), ValueConstructorVariant::ModuleConstant { .. } => todo!(),
ValueConstructorVariant::ModuleFn { name, module, .. } => { ValueConstructorVariant::ModuleFn { name, module, .. } => {
if self if self
@ -333,7 +284,7 @@ impl<'a> CodeGenerator<'a> {
pattern, pattern,
value, value,
scope_level.scope_increment(1), scope_level.scope_increment(1),
&vec![], &[],
), ),
TypedExpr::Try { .. } => todo!(), TypedExpr::Try { .. } => todo!(),
TypedExpr::When { TypedExpr::When {
@ -439,10 +390,6 @@ impl<'a> CodeGenerator<'a> {
.get(&(module.to_string(), current_var_name.clone())) .get(&(module.to_string(), current_var_name.clone()))
{ {
if current_scope.is_less_than(val, false) { if current_scope.is_less_than(val, false) {
println!(
"DATA USAGE HOLDER CHANGED 2 IS {:#?}",
self.uplc_data_usage_holder_lookup
);
self.uplc_data_usage_holder_lookup self.uplc_data_usage_holder_lookup
.insert((module, current_var_name), current_scope); .insert((module, current_var_name), current_scope);
} }
@ -503,9 +450,9 @@ impl<'a> CodeGenerator<'a> {
pattern: &TypedPattern, pattern: &TypedPattern,
value: &TypedExpr, value: &TypedExpr,
scope_level: ScopeLevels, scope_level: ScopeLevels,
vars: &Vec<TypedExpr>, vars: &[TypedExpr],
) { ) {
match dbg!(pattern) { match pattern {
Pattern::Int { .. } | Pattern::String { .. } | Pattern::Var { .. } => { Pattern::Int { .. } | Pattern::String { .. } | Pattern::Var { .. } => {
self.recurse_scope_level(value, scope_level); self.recurse_scope_level(value, scope_level);
} }
@ -543,10 +490,7 @@ impl<'a> CodeGenerator<'a> {
let mut mapping_index: IndexMap<String, usize> = IndexMap::new(); let mut mapping_index: IndexMap<String, usize> = IndexMap::new();
match constructor { match constructor {
tipo::PatternConstructor::Record { tipo::PatternConstructor::Record { field_map, .. } => {
name: _name,
field_map,
} => {
if let Some(fields_mapping) = field_map { if let Some(fields_mapping) = field_map {
mapping_index.extend(fields_mapping.fields.clone()); mapping_index.extend(fields_mapping.fields.clone());
mapping_index mapping_index
@ -556,8 +500,6 @@ impl<'a> CodeGenerator<'a> {
} }
}; };
println!("MAPPING INDEX IS {mapping_index:?}");
let module = module.clone().unwrap(); let module = module.clone().unwrap();
// TODO: support multiple subjects // TODO: support multiple subjects
let (var_name, tipo) = match &vars[0] { let (var_name, tipo) = match &vars[0] {
@ -596,7 +538,7 @@ impl<'a> CodeGenerator<'a> {
Pattern::Var { Pattern::Var {
name: field_name, .. name: field_name, ..
} => { } => {
let record_access = TypedExpr::RecordAccess { let record_access = TypedExpr::Assignment {
location: Span::empty(), location: Span::empty(),
tipo: Type::App { tipo: Type::App {
public: true, public: true,
@ -605,13 +547,23 @@ impl<'a> CodeGenerator<'a> {
args: vec![], args: vec![],
} }
.into(), .into(),
label: field_name.clone(), value: TypedExpr::RecordAccess {
location: Span::empty(),
tipo: Type::App {
public: true,
module: module.clone(),
name: constructor_name.to_string(),
args: vec![],
}
.into(),
label: label.clone(),
index, index,
record: TypedExpr::Var { record: TypedExpr::Var {
location: Span::empty(), location: Span::empty(),
constructor: tipo::ValueConstructor { constructor: tipo::ValueConstructor {
public: false, public: false,
variant: ValueConstructorVariant::LocalVariable { variant:
ValueConstructorVariant::LocalVariable {
location: Span::empty(), location: Span::empty(),
}, },
tipo: Type::App { tipo: Type::App {
@ -625,6 +577,13 @@ impl<'a> CodeGenerator<'a> {
name: var_name.clone(), name: var_name.clone(),
} }
.into(), .into(),
}
.into(),
pattern: TypedPattern::Var {
location: Span::empty(),
name: field_name.clone(),
},
kind: AssignmentKind::Let,
}; };
if let Some(val) = self.uplc_data_holder_lookup.get(&( if let Some(val) = self.uplc_data_holder_lookup.get(&(
@ -657,10 +616,6 @@ impl<'a> CodeGenerator<'a> {
.get(&(module.to_string(), var_name.clone())) .get(&(module.to_string(), var_name.clone()))
{ {
if scope_level.is_less_than(val, false) { if scope_level.is_less_than(val, false) {
println!(
"DATA USAGE HOLDER CHANGED 3 IS {:#?}",
self.uplc_data_usage_holder_lookup
);
self.uplc_data_usage_holder_lookup.insert( self.uplc_data_usage_holder_lookup.insert(
(module.to_string(), var_name.clone()), (module.to_string(), var_name.clone()),
scope_level.clone(), scope_level.clone(),
@ -1118,58 +1073,6 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::When { TypedExpr::When {
subjects, clauses, .. subjects, clauses, ..
} => { } => {
let current_clauses = clauses.clone();
let mut data_type = "".to_string();
let mut current_module = "".to_string();
let mut total_constr_length = 0;
let mut new_current_clauses: Vec<(usize, TypedExpr)> = current_clauses
.iter()
.map(|clause| {
let pattern = &clause.pattern[0];
let index = match pattern {
Pattern::Constructor {
name, tipo, module, ..
} => {
let mut is_app = false;
let mut tipo = &**tipo;
let mut key: (String, String) = ("".to_string(), "".to_string());
while !is_app {
match tipo {
Type::App { module, name, .. } => {
is_app = true;
key = (module.clone(), name.clone());
}
Type::Fn { ret, .. } => {
tipo = ret;
}
_ => todo!(),
};
}
let dt = self.data_types.get(&key).unwrap();
let index =
dt.constructors.iter().position(|c| name.clone() == c.name);
data_type = dt.name.clone();
current_module = module.clone().unwrap_or_default();
total_constr_length = dt.constructors.len();
index.unwrap_or(dt.constructors.len())
}
_ => todo!(),
};
(index, clause.then.clone())
})
.collect();
new_current_clauses.sort_by(|a, b| a.0.cmp(&b.0));
println!("NEW CURRENT CLAUSES {new_current_clauses:?}");
let subject = &subjects[0]; let subject = &subjects[0];
let mut is_var = false; let mut is_var = false;
@ -1208,6 +1111,104 @@ impl<'a> CodeGenerator<'a> {
} }
} }
let current_clauses = clauses.clone();
let mut current_module = "".to_string();
let mut total_constr_length = 0;
let pattern = &clauses[0].pattern[0];
let key = match pattern {
Pattern::Constructor { tipo, .. } => {
let mut is_app = false;
let mut tipo = &**tipo;
let mut key: (String, String) = ("".to_string(), "".to_string());
while !is_app {
match tipo {
Type::App { module, name, .. } => {
is_app = true;
key = (module.clone(), name.clone());
}
Type::Fn { ret, .. } => {
tipo = ret;
}
_ => todo!(),
};
}
key
}
_ => todo!(),
};
let dt = self.data_types.get(&key).unwrap();
let data_type = &dt.name;
let mut new_current_clauses: Vec<(usize, Term<Name>)> = current_clauses
.iter()
.map(|clause| {
let pattern = &clause.pattern[0];
let pair = match pattern {
Pattern::Constructor { name, module, .. } => {
let index =
dt.constructors.iter().position(|c| name.clone() == c.name);
let mut current_term = self.recurse_code_gen(
&clause.then,
scope_level.scope_increment_sequence(1),
);
if let Some(ind) = index {
for (index, field) in
dt.constructors[ind].arguments.iter().enumerate()
{
let label =
field.clone().label.unwrap_or(format!("{index}"));
if let Some((_, TypedExpr::Assignment { pattern, .. })) =
self.uplc_data_holder_lookup.get(&(
key.0.clone(),
current_var_name.to_string(),
label.clone(),
))
{
let var_name = match pattern {
Pattern::Var { name, .. } => name,
_ => todo!(),
};
current_term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: var_name.to_string(),
unique: 0.into(),
},
body: current_term.into(),
}
.into(),
argument: Term::Var(Name {
text: format!(
"{current_var_name}_field_{label}"
),
unique: 0.into(),
})
.into(),
};
}
}
}
current_module = module.clone().unwrap_or_default();
total_constr_length = dt.constructors.len();
(index.unwrap_or(dt.constructors.len()), current_term)
}
_ => todo!(),
};
pair
})
.collect();
new_current_clauses.sort_by(|a, b| a.0.cmp(&b.0));
let mut term = Term::Apply { let mut term = Term::Apply {
function: Term::Var(Name { function: Term::Var(Name {
text: format!("choose_{current_module}_{data_type}_constr"), text: format!("choose_{current_module}_{data_type}_constr"),
@ -1226,21 +1227,16 @@ impl<'a> CodeGenerator<'a> {
let mut new_current_clauses = new_current_clauses.to_vec(); let mut new_current_clauses = new_current_clauses.to_vec();
new_current_clauses.reverse(); new_current_clauses.reverse();
let last_term = let last_term = last.1.clone();
self.recurse_code_gen(&last.1, scope_level.scope_increment_sequence(1));
println!("NEW CURRENT CLAUSES AFTER SPLIT {new_current_clauses:?}"); let mut current: Option<(usize, Term<Name>)> = None;
let mut current: Option<(usize, TypedExpr)> = None;
for index in 0..total_constr_length - 1 { for index in 0..total_constr_length - 1 {
if current.is_none() { if current.is_none() {
current = new_current_clauses.pop(); current = new_current_clauses.pop();
} }
println!("CURRENT IS {current:?}");
if let Some(val) = current.clone() { if let Some(val) = current.clone() {
if val.0 == index { if val.0 == index {
let branch_term = self let branch_term = val.1;
.recurse_code_gen(&val.1, scope_level.scope_increment_sequence(1));
term = Term::Apply { term = Term::Apply {
function: term.into(), function: term.into(),
@ -1630,6 +1626,19 @@ impl<'a> CodeGenerator<'a> {
}; };
(index, name.clone()) (index, name.clone())
} }
TypedExpr::Assignment { value, .. } => match &**value {
TypedExpr::RecordAccess { index, tipo, .. } => {
let tipo = &**tipo;
let name = match tipo {
Type::App { name, .. } => name,
Type::Fn { .. } => todo!(),
Type::Var { .. } => todo!(),
};
(index, name.clone())
}
_ => todo!(),
},
_ => todo!(), _ => todo!(),
}; };

View File

@ -7,8 +7,9 @@ pub type ScriptContext {
} }
pub type Redeem { pub type Redeem {
Buy Buy { tipo: ByteArray, fin: Int }
Sell Sell { twice: ByteArray, find: Int }
Hold(Int)
} }
pub type Datum { pub type Datum {

View File

@ -33,8 +33,10 @@ pub fn spend(
rdmr: Redeemer, rdmr: Redeemer,
ctx: spend.ScriptContext, ctx: spend.ScriptContext,
) -> Bool { ) -> Bool {
let a = datum.fin let x = datum.rdmr
a when x is {
|> add_two sample.Buy(tipo1, fin) -> fin > 0
|> final_check sample.Sell(twice, find: fin) -> fin > 0
sample.Hold(some) -> some > 0
}
} }