feat: start when expressions

This commit is contained in:
rvcas 2022-11-27 16:54:59 -05:00 committed by Lucas
parent 8b24a66b7e
commit 86ea41adc3
5 changed files with 157 additions and 13 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
.idea .idea
_site/ _site/
temp

View File

@ -104,15 +104,18 @@ pub enum IR {
// }, // },
When { When {
count: usize, count: usize,
subject_name: String,
}, },
Clause { Clause {
count: usize, count: usize,
tipo: Arc<Type>,
subject_name: String,
}, },
Finally { Discard,
count: usize,
}, Finally,
If { If {
count: usize, count: usize,

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, ops::Deref, sync::Arc}; use std::{collections::HashMap, fmt::format, ops::Deref, sync::Arc};
use uplc::{ use uplc::{
ast::{ ast::{
@ -193,23 +193,38 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::When { TypedExpr::When {
subjects, clauses, .. subjects, clauses, ..
} => { } => {
let subject_name = format!("__subject_name_{}", self.id_gen.next());
// assuming one subject at the moment // assuming one subject at the moment
ir_stack.push(IR::When { ir_stack.push(IR::When {
count: clauses.len() + 1, count: clauses.len() + 1,
subject_name: subject_name.clone(),
}); });
let subject = subjects[0].clone(); let subject = subjects[0].clone();
self.build_ir(&subject, ir_stack); self.build_ir(&subject, ir_stack);
if let Some((last_clause, clauses)) = clauses.split_last() { if let Some((last_clause, clauses)) = clauses.split_last() {
let mut clauses_vec = vec![]; let mut clauses_vec = vec![];
let mut pattern_vec = vec![];
for clause in clauses { for clause in clauses {
ir_stack.push(IR::Clause { count: 2 });
self.build_ir(&clause.then, &mut clauses_vec); self.build_ir(&clause.then, &mut clauses_vec);
self.pattern_ir(&clause.pattern[0], ir_stack, &mut clauses_vec);
self.when_ir(
&clause.pattern[0],
&mut pattern_vec,
&mut clauses_vec,
&subject.tipo(),
subject_name.clone(),
)
} }
ir_stack.append(&mut pattern_vec);
let last_pattern = &last_clause.pattern[0]; let last_pattern = &last_clause.pattern[0];
ir_stack.push(IR::Finally { count: 2 }); ir_stack.push(IR::Finally);
self.build_ir(&last_clause.then, &mut clauses_vec); self.build_ir(&last_clause.then, &mut clauses_vec);
self.pattern_ir(last_pattern, ir_stack, &mut clauses_vec); self.pattern_ir(last_pattern, ir_stack, &mut clauses_vec);
@ -326,6 +341,38 @@ impl<'a> CodeGenerator<'a> {
} }
} }
fn when_ir(
&self,
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
pattern_vec: &mut Vec<IR>,
values: &mut Vec<IR>,
tipo: &Type,
subject_name: String,
) {
match pattern {
Pattern::Int { value, .. } => {
pattern_vec.push(IR::Clause {
count: 2,
tipo: tipo.clone().into(),
subject_name,
});
pattern_vec.push(IR::Int {
value: value.clone(),
});
pattern_vec.append(values);
}
Pattern::String { .. } => todo!(),
Pattern::Var { .. } => todo!(),
Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => unreachable!(),
Pattern::List { .. } => todo!(),
Pattern::Constructor { .. } => todo!(),
}
}
fn pattern_ir( fn pattern_ir(
&self, &self,
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>, pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
@ -338,7 +385,11 @@ impl<'a> CodeGenerator<'a> {
Pattern::Var { .. } => todo!(), Pattern::Var { .. } => todo!(),
Pattern::VarUsage { .. } => todo!(), Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(), Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => todo!(), Pattern::Discard { .. } => {
pattern_vec.push(IR::Discard);
pattern_vec.append(values);
}
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
let mut elements_vec = vec![]; let mut elements_vec = vec![];
@ -478,6 +529,9 @@ impl<'a> CodeGenerator<'a> {
} }
} }
}, },
IR::Discard => {
arg_stack.push(Term::Constant(Constant::Unit));
}
IR::List { count, tipo, tail } => { IR::List { count, tipo, tail } => {
let mut args = vec![]; let mut args = vec![];
@ -754,7 +808,7 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
IR::DefineFunc { func_name, .. } => { IR::DefineFunc { func_name, .. } => {
let body = arg_stack.pop().unwrap(); let _body = arg_stack.pop().unwrap();
todo!() todo!()
} }
@ -762,8 +816,70 @@ impl<'a> CodeGenerator<'a> {
IR::DefineConstrFields { .. } => todo!(), IR::DefineConstrFields { .. } => todo!(),
IR::DefineConstrFieldAccess { .. } => todo!(), IR::DefineConstrFieldAccess { .. } => todo!(),
IR::When { .. } => todo!(), IR::When { .. } => todo!(),
IR::Clause { .. } => todo!(), IR::Clause {
IR::Finally { .. } => todo!(), count,
tipo,
subject_name,
} => {
// clause to compare
let clause = arg_stack.pop().unwrap();
// the body to be run if the clause matches
let body = arg_stack.pop().unwrap();
// the final branch in the when expression
let mut term = arg_stack.pop().unwrap();
let checker = if tipo.is_int() {
DefaultFunction::EqualsInteger.into()
} else if tipo.is_bytearray() {
DefaultFunction::EqualsByteString.into()
} else if tipo.is_bool() {
todo!()
} else if tipo.is_string() {
DefaultFunction::EqualsString.into()
} else if tipo.is_list() {
todo!()
} else {
DefaultFunction::EqualsData.into()
};
term = Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(DefaultFunction::IfThenElse.into()).into(),
argument: Term::Apply {
function: Term::Apply {
function: checker,
argument: Term::Var(Name {
text: subject_name,
unique: 0.into(),
})
.into(),
}
.into(),
argument: clause.into(),
}
.into(),
}
.into(),
argument: body.into(),
}
.into(),
argument: term.into(),
}
.force_wrap();
arg_stack.push(term);
}
IR::Finally => {
let clause = arg_stack.pop().unwrap();
if !clause.is_unit() {
let _body = arg_stack.pop().unwrap();
todo!();
}
}
IR::If { .. } => todo!(), IR::If { .. } => todo!(),
IR::Constr { .. } => todo!(), IR::Constr { .. } => todo!(),
IR::Fields { .. } => todo!(), IR::Fields { .. } => todo!(),

View File

@ -110,6 +110,16 @@ pub enum Term<T> {
Builtin(DefaultFunction), Builtin(DefaultFunction),
} }
impl<T> Term<T> {
pub fn is_unit(&self) -> bool {
matches!(self, Term::Constant(Constant::Unit))
}
pub fn force_wrap(self) -> Self {
Term::Force(self.into())
}
}
impl<'a, T> Display for Term<T> impl<'a, T> Display for Term<T>
where where
T: Binder<'a>, T: Binder<'a>,

View File

@ -1,9 +1,11 @@
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, rc::Rc, str::FromStr};
use strum_macros::EnumIter; use strum_macros::EnumIter;
use flat_rs::de; use flat_rs::de;
use crate::ast::Term;
/// All the possible builtin functions in Untyped Plutus Core. /// All the possible builtin functions in Untyped Plutus Core.
#[repr(u8)] #[repr(u8)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -389,3 +391,15 @@ impl DefaultFunction {
.to_string() .to_string()
} }
} }
impl<T> From<DefaultFunction> for Term<T> {
fn from(builtin: DefaultFunction) -> Self {
Term::Builtin(builtin)
}
}
impl<T> From<DefaultFunction> for Rc<Term<T>> {
fn from(builtin: DefaultFunction) -> Self {
Term::Builtin(builtin).into()
}
}