checkpoint commit

This commit is contained in:
Kasey White 2022-11-05 22:21:00 -04:00 committed by Lucas
parent 9864a3fe31
commit e3fa9ac105
5 changed files with 238 additions and 153 deletions

1
Cargo.lock generated
View File

@ -70,6 +70,7 @@ name = "aiken-lang"
version = "0.0.24" version = "0.0.24"
dependencies = [ dependencies = [
"chumsky", "chumsky",
"indexmap",
"itertools", "itertools",
"miette", "miette",
"pretty_assertions", "pretty_assertions",

View File

@ -12,6 +12,7 @@ authors = ["Lucas Rosa <x@rvcas.dev>", "Kasey White <kwhitemsg@gmail.com>"]
[dependencies] [dependencies]
chumsky = "0.8.0" chumsky = "0.8.0"
indexmap = "1.9.1"
itertools = "0.10.5" itertools = "0.10.5"
miette = "5.2.0" miette = "5.2.0"
strum = "0.24.1" strum = "0.24.1"

View File

@ -1,5 +1,8 @@
use std::{collections::HashMap, fmt::format, rc::Rc, sync::Arc}; use std::{cmp::Ordering, collections::HashMap, rc::Rc, sync::Arc};
use indexmap::IndexMap;
use itertools::Itertools;
use uplc::{ use uplc::{
ast::{Constant, Name, Program, Term, Unique}, ast::{Constant, Name, Program, Term, Unique},
builtins::DefaultFunction, builtins::DefaultFunction,
@ -7,12 +10,12 @@ use uplc::{
}; };
use crate::{ use crate::{
ast::{self, DataType, Function, ModuleConstant, Pattern, TypeAlias, TypedArg, Use}, ast::{DataType, Function, ModuleConstant, Pattern, TypeAlias, TypedArg, Use},
expr::TypedExpr, expr::TypedExpr,
tipo::{self, ModuleValueConstructor, Type, ValueConstructorVariant}, tipo::{self, ModuleValueConstructor, Type, ValueConstructorVariant},
}; };
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ScopeLevels { pub struct ScopeLevels {
scope_tracker: Vec<i32>, scope_tracker: Vec<i32>,
} }
@ -71,9 +74,9 @@ impl Default for ScopeLevels {
pub struct CodeGenerator<'a> { pub struct CodeGenerator<'a> {
uplc_function_holder: Vec<(String, Term<Name>)>, uplc_function_holder: Vec<(String, Term<Name>)>,
uplc_function_holder_lookup: HashMap<(String, String), (ScopeLevels, TypedExpr)>, uplc_function_holder_lookup: IndexMap<(String, String), (ScopeLevels, TypedExpr)>,
uplc_data_holder_lookup: HashMap<(String, String, String), (ScopeLevels, TypedExpr)>, uplc_data_holder_lookup: IndexMap<(String, String, String), (ScopeLevels, TypedExpr)>,
uplc_data_usage_holder_lookup: HashMap<(String, String), ScopeLevels>, uplc_data_usage_holder_lookup: IndexMap<(String, String), ScopeLevels>,
functions: &'a HashMap<(String, String), &'a Function<Arc<tipo::Type>, TypedExpr>>, functions: &'a HashMap<(String, String), &'a Function<Arc<tipo::Type>, TypedExpr>>,
type_aliases: &'a HashMap<(String, String), &'a TypeAlias<Arc<tipo::Type>>>, type_aliases: &'a HashMap<(String, String), &'a TypeAlias<Arc<tipo::Type>>>,
data_types: &'a HashMap<(String, String), &'a DataType<Arc<tipo::Type>>>, data_types: &'a HashMap<(String, String), &'a DataType<Arc<tipo::Type>>>,
@ -91,9 +94,9 @@ impl<'a> CodeGenerator<'a> {
) -> Self { ) -> Self {
CodeGenerator { CodeGenerator {
uplc_function_holder: Vec::new(), uplc_function_holder: Vec::new(),
uplc_function_holder_lookup: HashMap::new(), uplc_function_holder_lookup: IndexMap::new(),
uplc_data_holder_lookup: HashMap::new(), uplc_data_holder_lookup: IndexMap::new(),
uplc_data_usage_holder_lookup: HashMap::new(), uplc_data_usage_holder_lookup: IndexMap::new(),
functions, functions,
type_aliases, type_aliases,
data_types, data_types,
@ -366,13 +369,10 @@ 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 dbg!(body) {
TypedExpr::Int { value, .. } => {} TypedExpr::Int { .. } => {}
TypedExpr::String { value, .. } => {} TypedExpr::String { .. } => {}
TypedExpr::ByteArray { bytes, .. } => {} TypedExpr::ByteArray { .. } => {}
TypedExpr::Sequence { TypedExpr::Sequence { expressions, .. } => {
location,
expressions,
} => {
// let mut terms = Vec::new(); // let mut terms = Vec::new();
for (i, exp) in expressions.iter().enumerate().rev() { for (i, exp) in expressions.iter().enumerate().rev() {
self.recurse_scope_level( self.recurse_scope_level(
@ -386,10 +386,21 @@ impl<'a> CodeGenerator<'a> {
expressions, expressions,
} => todo!(), } => todo!(),
TypedExpr::Var { TypedExpr::Var {
location, constructor, name, ..
constructor, } => match (constructor.variant.clone(), (*constructor.tipo).clone()) {
name, (ValueConstructorVariant::LocalVariable { .. }, Type::App { module, .. }) => {
} => {} if let Some(val) = self
.uplc_data_usage_holder_lookup
.get(&(module.to_string(), name.clone()))
{
if scope_level.is_less_than(val) {
self.uplc_data_usage_holder_lookup
.insert((module, name.clone()), scope_level.scope_increment(1));
}
}
}
_ => todo!(),
},
TypedExpr::Fn { TypedExpr::Fn {
location, location,
tipo, tipo,
@ -404,35 +415,20 @@ impl<'a> CodeGenerator<'a> {
elements, elements,
tail, tail,
} => todo!(), } => todo!(),
TypedExpr::Call { TypedExpr::Call { fun, args, .. } => {
location,
tipo,
fun,
args,
} => {
self.recurse_scope_level(fun, scope_level.scope_increment(args.len() as i32 + 1)); self.recurse_scope_level(fun, scope_level.scope_increment(args.len() as i32 + 1));
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
self.recurse_scope_level(&arg.value, scope_level.scope_increment(i as i32 + 1)); self.recurse_scope_level(&arg.value, scope_level.scope_increment(i as i32 + 1));
} }
} }
TypedExpr::BinOp { TypedExpr::BinOp { left, right, .. } => {
location,
tipo,
name,
left,
right,
} => {
self.recurse_scope_level(left, scope_level.clone()); self.recurse_scope_level(left, scope_level.clone());
self.recurse_scope_level(right, scope_level); self.recurse_scope_level(right, scope_level);
} }
TypedExpr::Assignment { TypedExpr::Assignment { value, pattern, .. } => {
location, self.recurse_scope_level_pattern(pattern, value, scope_level)
tipo, }
value,
pattern,
kind,
} => self.recurse_scope_level_pattern(pattern, value, scope_level),
TypedExpr::Try { TypedExpr::Try {
location, location,
tipo, tipo,
@ -455,6 +451,7 @@ impl<'a> CodeGenerator<'a> {
) )
} }
} }
todo!()
} }
//if statements increase scope due to branching. //if statements increase scope due to branching.
TypedExpr::If { TypedExpr::If {
@ -475,54 +472,80 @@ impl<'a> CodeGenerator<'a> {
self.recurse_scope_level(&branch.body, scope_level.scope_increment_sequence(1)); self.recurse_scope_level(&branch.body, scope_level.scope_increment_sequence(1));
} }
} }
a @ TypedExpr::RecordAccess { label, record, .. } => match &**record { a @ TypedExpr::RecordAccess { label, record, .. } => {
self.recurse_scope_level(record, scope_level.scope_increment(1));
let mut is_var = false;
let mut current_var_name = "".to_string();
let mut module = "".to_string();
let mut current_record = *record.clone();
while !is_var {
match current_record.clone() {
TypedExpr::Var { TypedExpr::Var {
constructor, name, .. constructor, name, ..
} => match (constructor.variant.clone(), (*constructor.tipo).clone()) { } => match (
(ValueConstructorVariant::LocalVariable { .. }, Type::App { module, .. }) => { constructor.clone().variant.clone(),
(*constructor.tipo).clone(),
) {
(
ValueConstructorVariant::LocalVariable { .. },
Type::App {
module: app_module, ..
},
) => {
current_var_name = if current_var_name.is_empty() {
name
} else {
format!("{name}_field_{current_var_name}")
};
is_var = true;
module = app_module.to_string();
}
_ => todo!(),
},
TypedExpr::RecordAccess { label, record, .. } => {
current_var_name = if current_var_name.is_empty() {
label.to_string()
} else {
format!("{label}_field_{current_var_name}")
};
current_record = *record.clone();
}
_ => {}
}
}
if let Some(val) = self.uplc_data_holder_lookup.get(&( if let Some(val) = self.uplc_data_holder_lookup.get(&(
module.clone(), module.to_string(),
name.clone(), current_var_name.clone(),
label.clone(), label.clone(),
)) { )) {
if scope_level.is_less_than(&val.0) { if scope_level.is_less_than(&val.0) {
self.uplc_data_holder_lookup.insert( self.uplc_data_holder_lookup.insert(
(module.clone(), name.clone(), label.clone()), (module.to_string(), current_var_name.clone(), label.clone()),
(scope_level.clone(), a.clone()), (scope_level.clone(), a.clone()),
); );
} }
} else { } else {
self.uplc_data_holder_lookup.insert( self.uplc_data_holder_lookup.insert(
(module.clone(), name.clone(), label.clone()), (module.to_string(), current_var_name.clone(), label.clone()),
(scope_level.clone(), a.clone()), (scope_level.clone(), a.clone()),
); );
} }
if let Some(val) = self if let Some(val) = self
.uplc_data_usage_holder_lookup .uplc_data_usage_holder_lookup
.get(&(module.clone(), name.clone())) .get(&(module.to_string(), current_var_name.clone()))
{ {
if scope_level.is_less_than(val) { if scope_level.is_less_than(val) {
self.uplc_data_usage_holder_lookup self.uplc_data_usage_holder_lookup
.insert((module, name.clone()), scope_level); .insert((module, current_var_name.clone()), scope_level);
} }
} else { } else {
self.uplc_data_usage_holder_lookup self.uplc_data_usage_holder_lookup
.insert((module, name.clone()), scope_level); .insert((module, current_var_name), scope_level);
} }
} }
_ => todo!(), a @ TypedExpr::ModuleSelect { constructor, .. } => match constructor {
},
_ => todo!(),
},
a @ TypedExpr::ModuleSelect {
location,
tipo,
label,
module_name,
module_alias,
constructor,
} => match constructor {
ModuleValueConstructor::Record { ModuleValueConstructor::Record {
name, name,
arity, arity,
@ -530,14 +553,11 @@ impl<'a> CodeGenerator<'a> {
field_map, field_map,
location, location,
} => todo!(), } => todo!(),
ModuleValueConstructor::Fn { ModuleValueConstructor::Fn { module, name, .. } => {
location, if self
module,
name,
} => {
if !self
.uplc_function_holder_lookup .uplc_function_holder_lookup
.contains_key(&(module.to_string(), name.to_string())) .get(&(module.to_string(), name.to_string()))
.is_none()
{ {
let func_def = self let func_def = self
.functions .functions
@ -551,11 +571,9 @@ impl<'a> CodeGenerator<'a> {
self.uplc_function_holder_lookup.insert( self.uplc_function_holder_lookup.insert(
(module.to_string(), name.to_string()), (module.to_string(), name.to_string()),
(scope_level.clone(), a.clone()), (scope_level, a.clone()),
); );
} } else if scope_level.is_less_than(
if scope_level.is_less_than(
&self &self
.uplc_function_holder_lookup .uplc_function_holder_lookup
.get(&(module.to_string(), name.to_string())) .get(&(module.to_string(), name.to_string()))
@ -936,26 +954,49 @@ impl<'a> CodeGenerator<'a> {
} }
self.maybe_insert_def(final_if_term, scope_level) self.maybe_insert_def(final_if_term, scope_level)
} }
TypedExpr::RecordAccess { TypedExpr::RecordAccess { label, record, .. } => {
location, let mut is_var = false;
tipo, let mut current_var_name = "".to_string();
label, let mut current_record = *record.clone();
index, while !is_var {
record, match current_record.clone() {
} => match &**record {
TypedExpr::Var { TypedExpr::Var {
constructor, name, .. constructor, name, ..
} => match (constructor.variant.clone(), (*constructor.tipo).clone()) { } => match (
(ValueConstructorVariant::LocalVariable { .. }, Type::App { module, .. }) => { constructor.clone().variant.clone(),
Term::Var(Name { (*constructor.tipo).clone(),
text: format!("{name}_field_{label}"), ) {
unique: 0.into(), (
}) ValueConstructorVariant::LocalVariable { .. },
Type::App {
module: app_module, ..
},
) => {
current_var_name = if current_var_name.is_empty() {
name
} else {
format!("{name}_field_{current_var_name}")
};
is_var = true;
} }
_ => todo!(), _ => todo!(),
}, },
_ => todo!(), TypedExpr::RecordAccess { label, record, .. } => {
}, current_var_name = if current_var_name.is_empty() {
label.to_string()
} else {
format!("{label}_field_{current_var_name}")
};
current_record = *record.clone();
}
_ => {}
}
}
Term::Var(Name {
text: format!("{current_var_name}_field_{label}"),
unique: 0.into(),
})
}
TypedExpr::ModuleSelect { TypedExpr::ModuleSelect {
location, location,
tipo, tipo,
@ -1042,48 +1083,59 @@ impl<'a> CodeGenerator<'a> {
.into(), .into(),
argument: function_body.into(), argument: function_body.into(),
}; };
self.uplc_function_holder_lookup.remove(func); self.uplc_function_holder_lookup.shift_remove(func);
} }
} }
for (key, (record_scope_level, expr)) in self.uplc_data_holder_lookup.clone().iter() { // Pull out all uplc data holder and data usage, Sort By Scope Level, Then
if scope_level.is_less_than(record_scope_level) { let mut data_holder: Vec<((String, String, String), (bool, ScopeLevels, u64))> = self
let local_var_name = &key.1; .uplc_data_holder_lookup
let field = &key.2; .iter()
term = Term::Apply { .filter(|record_scope| scope_level.is_less_than(&record_scope.1 .0))
function: Term::Lambda { .map(|((module, name, label), (scope, expr))| {
parameter_name: Name { let index = match expr {
text: format!("{local_var_name}_field_{field}"), TypedExpr::RecordAccess { index, .. } => index,
unique: 0.into(), _ => todo!(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Var(Name {
text: "constr_field_get_arg".to_string(),
unique: 0.into(),
})
.into(),
argument: Term::Var(Name {
text: format!("{local_var_name}_fields"),
unique: 0.into(),
})
.into(),
}
.into(),
}; };
self.uplc_data_holder_lookup.remove(key); (
} (module.to_string(), name.to_string(), label.to_string()),
} (false, scope.clone(), *index),
)
})
.collect();
for (key, record_fields_scope) in self.uplc_data_usage_holder_lookup.clone().iter() { data_holder.extend(
if scope_level.is_less_than(record_fields_scope) { self.uplc_data_usage_holder_lookup
let local_var_name = &key.1; .iter()
.filter(|record_scope| scope_level.is_less_than(&record_scope.1))
.map(|((module, name), scope)| {
(
(module.to_string(), name.to_string(), "".to_string()),
(true, scope.clone(), 0),
)
})
.collect::<Vec<((String, String, String), (bool, ScopeLevels, u64))>>(),
);
data_holder.sort_by(|b, d| {
if b.1 .1.is_less_than(&d.1 .1) {
Ordering::Less
} else if d.1 .1.is_less_than(&b.1 .1) {
Ordering::Greater
} else if b.1 .0 && !d.1 .0 {
Ordering::Less
} else if !b.1 .0 && d.1 .0 {
Ordering::Greater
} else {
Ordering::Equal
}
});
for (key @ (module, name, label), (is_data_usage, _, index)) in data_holder.iter() {
if *is_data_usage {
term = Term::Apply { term = Term::Apply {
function: Term::Lambda { function: Term::Lambda {
parameter_name: Name { parameter_name: Name {
text: format!("{local_var_name}_fields"), text: format!("{name}_fields"),
unique: 0.into(), unique: 0.into(),
}, },
body: term.into(), body: term.into(),
@ -1097,14 +1149,45 @@ impl<'a> CodeGenerator<'a> {
}) })
.into(), .into(),
argument: Term::Var(Name { argument: Term::Var(Name {
text: local_var_name.to_string(), text: name.to_string(),
unique: 0.into(), unique: 0.into(),
}) })
.into(), .into(),
} }
.into(), .into(),
}; };
self.uplc_data_usage_holder_lookup.remove(key);
self.uplc_data_usage_holder_lookup
.shift_remove(&(module.clone(), name.clone()));
} else {
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!("{name}_field_{label}"),
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Apply {
function: Term::Var(Name {
text: "constr_field_get_arg".to_string(),
unique: 0.into(),
})
.into(),
argument: Term::Var(Name {
text: format!("{name}_fields"),
unique: 0.into(),
})
.into(),
}
.into(),
argument: Term::Constant(Constant::Integer(*index as i128)).into(),
}
.into(),
};
self.uplc_data_holder_lookup.shift_remove(key);
} }
} }

View File

@ -3,7 +3,7 @@ pub type ScriptContext {
} }
pub type Datum { pub type Datum {
something: ByteArray, something: ScriptContext,
fin: Int fin: Int
} }

View File

@ -12,7 +12,7 @@ pub fn spend(datum: sample.Datum, rdmr: Redeemer, ctx: spend.ScriptContext) -> B
let y = 2 let y = 2
let x = 1 let x = 1
let a = datum.something let a = datum.something.thing
let b = 2 let b = 2
b == 1 b == 1
} }