out with the old code and in with the air tree

This commit is contained in:
microproofs 2023-07-25 12:13:32 -04:00 committed by Kasey
parent 02ce3761ae
commit 55dd1a1a56
13 changed files with 3395 additions and 8318 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,55 +7,42 @@ use crate::{
tipo::{Type, ValueConstructor}, tipo::{Type, ValueConstructor},
}; };
use super::scope::Scope;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Air { pub enum Air {
// Primitives // Primitives
Int { Int {
scope: Scope,
value: String, value: String,
}, },
String { String {
scope: Scope,
value: String, value: String,
}, },
ByteArray { ByteArray {
scope: Scope,
bytes: Vec<u8>, bytes: Vec<u8>,
}, },
Bool { Bool {
scope: Scope,
value: bool, value: bool,
}, },
List { List {
scope: Scope,
count: usize, count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
tail: bool, tail: bool,
}, },
Tuple { Tuple {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
count: usize, count: usize,
}, },
Void { Void,
scope: Scope,
},
Var { Var {
scope: Scope,
constructor: ValueConstructor, constructor: ValueConstructor,
name: String, name: String,
variant_name: String, variant_name: String,
}, },
// Functions // Functions
Call { Call {
scope: Scope,
count: usize, count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
DefineFunc { DefineFunc {
scope: Scope,
func_name: String, func_name: String,
module_name: String, module_name: String,
params: Vec<String>, params: Vec<String>,
@ -63,71 +50,58 @@ pub enum Air {
variant_name: String, variant_name: String,
}, },
Fn { Fn {
scope: Scope,
params: Vec<String>, params: Vec<String>,
}, },
Builtin { Builtin {
scope: Scope,
count: usize, count: usize,
func: DefaultFunction, func: DefaultFunction,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Operators // Operators
BinOp { BinOp {
scope: Scope,
name: BinOp, name: BinOp,
tipo: Arc<Type>, tipo: Arc<Type>,
argument_tipo: Arc<Type>,
}, },
UnOp { UnOp {
scope: Scope,
op: UnOp, op: UnOp,
}, },
// Assignment // Assignment
Let { Let {
scope: Scope,
name: String, name: String,
}, },
UnWrapData { UnWrapData {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
WrapData { WrapData {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
AssertConstr { AssertConstr {
scope: Scope,
constr_index: usize, constr_index: usize,
}, },
AssertBool { AssertBool {
scope: Scope,
is_true: bool, is_true: bool,
}, },
// When // When
When { When {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
subject_tipo: Arc<Type>,
}, },
Clause { Clause {
scope: Scope, subject_tipo: Arc<Type>,
tipo: Arc<Type>,
subject_name: String, subject_name: String,
complex_clause: bool, complex_clause: bool,
}, },
ListClause { ListClause {
scope: Scope, subject_tipo: Arc<Type>,
tipo: Arc<Type>,
tail_name: String, tail_name: String,
next_tail_name: Option<String>, next_tail_name: Option<String>,
complex_clause: bool, complex_clause: bool,
}, },
WrapClause { WrapClause,
scope: Scope,
},
TupleClause { TupleClause {
scope: Scope, subject_tipo: Arc<Type>,
tipo: Arc<Type>,
indices: IndexSet<(usize, String)>, indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>, predefined_indices: IndexSet<(usize, String)>,
subject_name: String, subject_name: String,
@ -135,296 +109,76 @@ pub enum Air {
complex_clause: bool, complex_clause: bool,
}, },
ClauseGuard { ClauseGuard {
scope: Scope,
subject_name: String, subject_name: String,
tipo: Arc<Type>, subject_tipo: Arc<Type>,
}, },
ListClauseGuard { ListClauseGuard {
scope: Scope, subject_tipo: Arc<Type>,
tipo: Arc<Type>,
tail_name: String, tail_name: String,
next_tail_name: Option<String>, next_tail_name: Option<String>,
inverse: bool, inverse: bool,
}, },
Finally { TupleGuard {
scope: Scope, subject_tipo: Arc<Type>,
indices: IndexSet<(usize, String)>,
subject_name: String,
type_count: usize,
}, },
Finally,
// If // If
If { If {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Record Creation // Record Creation
Record { Constr {
scope: Scope,
tag: usize, tag: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
count: usize, count: usize,
}, },
RecordUpdate { RecordUpdate {
scope: Scope,
highest_index: usize, highest_index: usize,
indices: Vec<(usize, Arc<Type>)>, indices: Vec<(usize, Arc<Type>)>,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Field Access // Field Access
RecordAccess { RecordAccess {
scope: Scope,
record_index: u64, record_index: u64,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
FieldsExpose { FieldsExpose {
scope: Scope,
indices: Vec<(usize, String, Arc<Type>)>, indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool, check_last_item: bool,
}, },
// ListAccess // ListAccess
ListAccessor { ListAccessor {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
names: Vec<String>, names: Vec<String>,
tail: bool, tail: bool,
check_last_item: bool, check_last_item: bool,
}, },
ListExpose { ListExpose {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>, tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>, tail: Option<(String, String)>,
}, },
// Tuple Access // Tuple Access
TupleAccessor { TupleAccessor {
scope: Scope,
names: Vec<String>, names: Vec<String>,
tipo: Arc<Type>, tipo: Arc<Type>,
check_last_item: bool, check_last_item: bool,
}, },
TupleIndex { TupleIndex {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tuple_index: usize, tuple_index: usize,
}, },
// Misc. // Misc.
ErrorTerm { ErrorTerm {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
Trace { Trace {
scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
NoOp { NoOp,
scope: Scope, FieldsEmpty,
}, ListEmpty,
FieldsEmpty {
scope: Scope,
},
ListEmpty {
scope: Scope,
},
}
impl Air {
pub fn scope(&self) -> Scope {
match self {
Air::Int { scope, .. }
| Air::String { scope, .. }
| Air::ByteArray { scope, .. }
| Air::Bool { scope, .. }
| Air::List { scope, .. }
| Air::Tuple { scope, .. }
| Air::Void { scope }
| Air::Var { scope, .. }
| Air::Call { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Fn { scope, .. }
| Air::Builtin { scope, .. }
| Air::BinOp { scope, .. }
| Air::UnOp { scope, .. }
| Air::Let { scope, .. }
| Air::UnWrapData { scope, .. }
| Air::WrapData { scope, .. }
| Air::AssertConstr { scope, .. }
| Air::AssertBool { scope, .. }
| Air::When { scope, .. }
| Air::Clause { scope, .. }
| Air::ListClause { scope, .. }
| Air::WrapClause { scope }
| Air::TupleClause { scope, .. }
| Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. }
| Air::Finally { scope }
| Air::If { scope, .. }
| Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. }
| Air::FieldsEmpty { scope }
| Air::ListEmpty { scope }
| Air::ListAccessor { scope, .. }
| Air::ListExpose { scope, .. }
| Air::TupleAccessor { scope, .. }
| Air::TupleIndex { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::Trace { scope, .. }
| Air::NoOp { scope, .. } => scope.clone(),
}
}
pub fn scope_mut(&mut self) -> &mut Scope {
match self {
Air::Int { scope, .. }
| Air::String { scope, .. }
| Air::ByteArray { scope, .. }
| Air::Bool { scope, .. }
| Air::List { scope, .. }
| Air::Tuple { scope, .. }
| Air::Void { scope }
| Air::Var { scope, .. }
| Air::Call { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Fn { scope, .. }
| Air::Builtin { scope, .. }
| Air::BinOp { scope, .. }
| Air::UnOp { scope, .. }
| Air::Let { scope, .. }
| Air::UnWrapData { scope, .. }
| Air::WrapData { scope, .. }
| Air::AssertConstr { scope, .. }
| Air::AssertBool { scope, .. }
| Air::When { scope, .. }
| Air::Clause { scope, .. }
| Air::ListClause { scope, .. }
| Air::WrapClause { scope }
| Air::TupleClause { scope, .. }
| Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. }
| Air::Finally { scope }
| Air::If { scope, .. }
| Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. }
| Air::FieldsEmpty { scope }
| Air::ListEmpty { scope }
| Air::ListAccessor { scope, .. }
| Air::ListExpose { scope, .. }
| Air::TupleAccessor { scope, .. }
| Air::TupleIndex { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::Trace { scope, .. }
| Air::NoOp { scope, .. } => scope,
}
}
pub fn tipo(&self) -> Option<Arc<Type>> {
match self {
Air::Int { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
Air::String { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "String".to_string(),
args: vec![],
}
.into(),
),
Air::ByteArray { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "ByteArray".to_string(),
args: vec![],
}
.into(),
),
Air::Bool { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
Air::Void { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Void".to_string(),
args: vec![],
}
.into(),
),
Air::WrapData { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Data".to_string(),
args: vec![],
}
.into(),
),
Air::Var { constructor, .. } => Some(constructor.tipo.clone()),
Air::List { tipo, .. }
| Air::Tuple { tipo, .. }
| Air::Call { tipo, .. }
| Air::Builtin { tipo, .. }
| Air::BinOp { tipo, .. }
| Air::UnWrapData { tipo, .. }
| Air::When { tipo, .. }
| Air::Clause { tipo, .. }
| Air::ListClause { tipo, .. }
| Air::TupleClause { tipo, .. }
| Air::ClauseGuard { tipo, .. }
| Air::If { tipo, .. }
| Air::ListClauseGuard { tipo, .. }
| Air::Record { tipo, .. }
| Air::RecordUpdate { tipo, .. }
| Air::RecordAccess { tipo, .. }
| Air::ListAccessor { tipo, .. }
| Air::ListExpose { tipo, .. }
| Air::TupleAccessor { tipo, .. }
| Air::TupleIndex { tipo, .. }
| Air::ErrorTerm { tipo, .. }
| Air::Trace { tipo, .. } => Some(tipo.clone()),
Air::DefineFunc { .. }
| Air::Fn { .. }
| Air::Let { .. }
| Air::WrapClause { .. }
| Air::AssertConstr { .. }
| Air::AssertBool { .. }
| Air::Finally { .. }
| Air::FieldsExpose { .. }
| Air::FieldsEmpty { .. }
| Air::ListEmpty { .. }
| Air::NoOp { .. } => None,
Air::UnOp { op, .. } => match op {
UnOp::Not => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
UnOp::Negate => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
},
}
}
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,184 +0,0 @@
use indexmap::IndexSet;
use std::sync::Arc;
use uplc::builtins::DefaultFunction;
use crate::{
ast::{BinOp, UnOp},
tipo::{Type, ValueConstructor},
};
#[derive(Debug, Clone, PartialEq)]
pub enum Air {
// Primitives
Int {
value: String,
},
String {
value: String,
},
ByteArray {
bytes: Vec<u8>,
},
Bool {
value: bool,
},
List {
count: usize,
tipo: Arc<Type>,
tail: bool,
},
Tuple {
tipo: Arc<Type>,
count: usize,
},
Void,
Var {
constructor: ValueConstructor,
name: String,
variant_name: String,
},
// Functions
Call {
count: usize,
tipo: Arc<Type>,
},
DefineFunc {
func_name: String,
module_name: String,
params: Vec<String>,
recursive: bool,
variant_name: String,
},
Fn {
params: Vec<String>,
},
Builtin {
count: usize,
func: DefaultFunction,
tipo: Arc<Type>,
},
// Operators
BinOp {
name: BinOp,
tipo: Arc<Type>,
argument_tipo: Arc<Type>,
},
UnOp {
op: UnOp,
},
// Assignment
Let {
name: String,
},
UnWrapData {
tipo: Arc<Type>,
},
WrapData {
tipo: Arc<Type>,
},
AssertConstr {
constr_index: usize,
},
AssertBool {
is_true: bool,
},
// When
When {
tipo: Arc<Type>,
subject_name: String,
subject_tipo: Arc<Type>,
},
Clause {
subject_tipo: Arc<Type>,
subject_name: String,
complex_clause: bool,
},
ListClause {
subject_tipo: Arc<Type>,
tail_name: String,
next_tail_name: Option<String>,
complex_clause: bool,
},
WrapClause,
TupleClause {
subject_tipo: Arc<Type>,
indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>,
subject_name: String,
count: usize,
complex_clause: bool,
},
ClauseGuard {
subject_name: String,
subject_tipo: Arc<Type>,
},
ListClauseGuard {
subject_tipo: Arc<Type>,
tail_name: String,
next_tail_name: Option<String>,
inverse: bool,
},
TupleGuard {
subject_tipo: Arc<Type>,
indices: IndexSet<(usize, String)>,
subject_name: String,
type_count: usize,
},
Finally,
// If
If {
tipo: Arc<Type>,
},
// Record Creation
Constr {
tag: usize,
tipo: Arc<Type>,
count: usize,
},
RecordUpdate {
highest_index: usize,
indices: Vec<(usize, Arc<Type>)>,
tipo: Arc<Type>,
},
// Field Access
RecordAccess {
record_index: u64,
tipo: Arc<Type>,
},
FieldsExpose {
indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
},
// ListAccess
ListAccessor {
tipo: Arc<Type>,
names: Vec<String>,
tail: bool,
check_last_item: bool,
},
ListExpose {
tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
},
// Tuple Access
TupleAccessor {
names: Vec<String>,
tipo: Arc<Type>,
check_last_item: bool,
},
TupleIndex {
tipo: Arc<Type>,
tuple_index: usize,
},
// Misc.
ErrorTerm {
tipo: Arc<Type>,
},
Trace {
tipo: Arc<Type>,
},
NoOp,
FieldsEmpty,
ListEmpty,
}

View File

@ -1,366 +0,0 @@
use std::sync::Arc;
use indexmap::IndexMap;
use crate::{
ast::TypedDataType,
builtins::bool,
gen_uplc::builder::{lookup_data_type_by_tipo, DataTypeKey, FunctionAccessKey},
tipo::TypeVar,
};
use crate::{
ast::{BinOp, ClauseGuard, Constant, UnOp},
tipo::Type,
};
use super::tree::{AirExpression, AirStatement, AirTree};
#[derive(Clone, Debug)]
pub enum CodeGenFunction {
Function { body: AirTree, params: Vec<String> },
Link(String),
}
#[derive(Clone, Debug)]
pub enum UserFunction {
Function(AirTree, Vec<(FunctionAccessKey, String)>),
Link(String),
}
pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Arc<Type>)> {
let mut generics_ids = vec![];
if let Some(id) = tipo.get_generic() {
generics_ids.push((id, param.clone().into()));
return generics_ids;
}
for (tipo, param_type) in tipo
.get_inner_types()
.iter()
.zip(param.get_inner_types().iter())
{
generics_ids.append(&mut get_generic_id_and_type(tipo, param_type));
}
generics_ids
}
pub fn convert_opaque_type(
t: &Arc<Type>,
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
) -> Arc<Type> {
if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) {
let data_type = lookup_data_type_by_tipo(data_types, t).unwrap();
let new_type_fields = data_type.typed_parameters;
let mono_types: IndexMap<u64, Arc<Type>>;
let mut mono_type_vec = vec![];
for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) {
mono_type_vec.append(&mut get_generic_id_and_type(tipo, &param));
}
mono_types = mono_type_vec.into_iter().collect();
let generic_type = &data_type.constructors[0].arguments[0].tipo;
let mono_type = find_and_replace_generics(generic_type, &mono_types);
convert_opaque_type(&mono_type, data_types)
} else {
match t.as_ref() {
Type::App {
public,
module,
name,
args,
} => {
let mut new_args = vec![];
for arg in args {
let arg = convert_opaque_type(arg, data_types);
new_args.push(arg);
}
Type::App {
public: *public,
module: module.clone(),
name: name.clone(),
args: new_args,
}
.into()
}
Type::Fn { args, ret } => {
let mut new_args = vec![];
for arg in args {
let arg = convert_opaque_type(arg, data_types);
new_args.push(arg);
}
let ret = convert_opaque_type(ret, data_types);
Type::Fn {
args: new_args,
ret,
}
.into()
}
Type::Var { tipo: var_tipo } => {
if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() {
convert_opaque_type(tipo, data_types)
} else {
t.clone()
}
}
Type::Tuple { elems } => {
let mut new_elems = vec![];
for arg in elems {
let arg = convert_opaque_type(arg, data_types);
new_elems.push(arg);
}
Type::Tuple { elems: new_elems }.into()
}
}
}
}
pub fn check_replaceable_opaque_type(
t: &Arc<Type>,
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
) -> bool {
let data_type = lookup_data_type_by_tipo(data_types, t);
if let Some(data_type) = data_type {
let data_type_args = &data_type.constructors[0].arguments;
data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1
} else {
false
}
}
pub fn find_and_replace_generics(
tipo: &Arc<Type>,
mono_types: &IndexMap<u64, Arc<Type>>,
) -> Arc<Type> {
if let Some(id) = tipo.get_generic() {
// If a generic does not have a type we know of
// like a None in option then just use same type
mono_types.get(&id).unwrap_or(tipo).clone()
} else if tipo.is_generic() {
match &**tipo {
Type::App {
args,
public,
module,
name,
} => {
let mut new_args = vec![];
for arg in args {
let arg = find_and_replace_generics(arg, mono_types);
new_args.push(arg);
}
let t = Type::App {
args: new_args,
public: *public,
module: module.clone(),
name: name.clone(),
};
t.into()
}
Type::Fn { args, ret } => {
let mut new_args = vec![];
for arg in args {
let arg = find_and_replace_generics(arg, mono_types);
new_args.push(arg);
}
let ret = find_and_replace_generics(ret, mono_types);
let t = Type::Fn {
args: new_args,
ret,
};
t.into()
}
Type::Tuple { elems } => {
let mut new_elems = vec![];
for elem in elems {
let elem = find_and_replace_generics(elem, mono_types);
new_elems.push(elem);
}
let t = Type::Tuple { elems: new_elems };
t.into()
}
Type::Var { tipo: var_tipo } => {
let var_type = var_tipo.as_ref().borrow().clone();
match var_type {
TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types),
TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(),
}
}
}
} else {
tipo.clone()
}
}
pub fn constants_ir(literal: &Constant) -> AirTree {
match literal {
Constant::Int { value, .. } => AirTree::int(value),
Constant::String { value, .. } => AirTree::string(value),
Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()),
}
}
pub fn handle_clause_guard(clause_guard: &ClauseGuard<Arc<Type>>) -> AirTree {
match clause_guard {
ClauseGuard::Not { value, .. } => {
let val = handle_clause_guard(value);
AirTree::unop(UnOp::Not, val)
}
ClauseGuard::Equals { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::Eq, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::NotEquals { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::NotEq, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::GtInt { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::GtInt, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::GtEqInt { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::GtEqInt, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::LtInt { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::LtInt, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::LtEqInt { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::LtEqInt, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::Or { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::Or, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::And { left, right, .. } => {
let left_child = handle_clause_guard(left);
let right_child = handle_clause_guard(right);
AirTree::binop(BinOp::And, bool(), left_child, right_child, left.tipo())
}
ClauseGuard::Var { tipo, name, .. } => AirTree::local_var(name, tipo.clone()),
ClauseGuard::Constant(constant) => constants_ir(constant),
}
}
pub fn get_variant_name(t: &Arc<Type>) -> String {
if t.is_string() {
"_string".to_string()
} else if t.is_int() {
"_int".to_string()
} else if t.is_bool() {
"_bool".to_string()
} else if t.is_bytearray() {
"_bytearray".to_string()
} else if t.is_map() {
let mut full_type = vec!["_map".to_string()];
let pair_type = &t.get_inner_types()[0];
let fst_type = &pair_type.get_inner_types()[0];
let snd_type = &pair_type.get_inner_types()[1];
full_type.push(get_variant_name(fst_type));
full_type.push(get_variant_name(snd_type));
full_type.join("")
} else if t.is_list() {
let full_type = "_list".to_string();
let list_type = &t.get_inner_types()[0];
format!("{}{}", full_type, get_variant_name(list_type))
} else if t.is_tuple() {
let mut full_type = vec!["_tuple".to_string()];
let inner_types = t.get_inner_types();
for arg_type in inner_types {
full_type.push(get_variant_name(&arg_type));
}
full_type.join("")
} else if t.is_unbound() {
"_unbound".to_string()
} else {
let full_type = "_data".to_string();
if t.is_generic() {
println!("FULL TYPE: {:#?}", t);
panic!("FOUND A POLYMORPHIC TYPE. EXPECTED MONOMORPHIC TYPE");
}
full_type
}
}
pub fn monomorphize(air_tree: &mut AirTree, mono_types: &IndexMap<u64, Arc<Type>>) {
let mut held_types = air_tree.mut_held_types();
while let Some(tipo) = held_types.pop() {
*tipo = find_and_replace_generics(tipo, mono_types);
}
}
pub fn erase_opaque_type_operations(
air_tree: &mut AirTree,
data_types: &IndexMap<DataTypeKey, &TypedDataType>,
) {
if let AirTree::Expression(e) = air_tree {
match e {
AirExpression::Constr { tipo, args, .. } => {
if check_replaceable_opaque_type(tipo, data_types) {
*air_tree = args.pop().unwrap();
}
}
AirExpression::RecordAccess { tipo, record, .. } => {
if check_replaceable_opaque_type(tipo, data_types) {
*air_tree = (**record).clone();
}
}
_ => {}
}
} else if let AirTree::Statement {
statement: AirStatement::FieldsExpose {
record, indices, ..
},
hoisted_over: Some(hoisted_over),
} = air_tree
{
if check_replaceable_opaque_type(&record.return_type(), data_types) {
let name = indices[0].1.clone();
*air_tree = AirTree::let_assignment(name, (**record).clone())
.hoist_over((**hoisted_over).clone())
}
}
let mut held_types = air_tree.mut_held_types();
while let Some(tipo) = held_types.pop() {
*tipo = convert_opaque_type(tipo, data_types);
}
}

View File

@ -0,0 +1,430 @@
use indexmap::IndexSet;
use std::sync::Arc;
use uplc::builtins::DefaultFunction;
use crate::{
ast::{BinOp, UnOp},
tipo::{Type, ValueConstructor},
};
use super::scope::Scope;
#[derive(Debug, Clone, PartialEq)]
pub enum Air {
// Primitives
Int {
scope: Scope,
value: String,
},
String {
scope: Scope,
value: String,
},
ByteArray {
scope: Scope,
bytes: Vec<u8>,
},
Bool {
scope: Scope,
value: bool,
},
List {
scope: Scope,
count: usize,
tipo: Arc<Type>,
tail: bool,
},
Tuple {
scope: Scope,
tipo: Arc<Type>,
count: usize,
},
Void {
scope: Scope,
},
Var {
scope: Scope,
constructor: ValueConstructor,
name: String,
variant_name: String,
},
// Functions
Call {
scope: Scope,
count: usize,
tipo: Arc<Type>,
},
DefineFunc {
scope: Scope,
func_name: String,
module_name: String,
params: Vec<String>,
recursive: bool,
variant_name: String,
},
Fn {
scope: Scope,
params: Vec<String>,
},
Builtin {
scope: Scope,
count: usize,
func: DefaultFunction,
tipo: Arc<Type>,
},
// Operators
BinOp {
scope: Scope,
name: BinOp,
tipo: Arc<Type>,
},
UnOp {
scope: Scope,
op: UnOp,
},
// Assignment
Let {
scope: Scope,
name: String,
},
UnWrapData {
scope: Scope,
tipo: Arc<Type>,
},
WrapData {
scope: Scope,
tipo: Arc<Type>,
},
AssertConstr {
scope: Scope,
constr_index: usize,
},
AssertBool {
scope: Scope,
is_true: bool,
},
// When
When {
scope: Scope,
tipo: Arc<Type>,
subject_name: String,
},
Clause {
scope: Scope,
tipo: Arc<Type>,
subject_name: String,
complex_clause: bool,
},
ListClause {
scope: Scope,
tipo: Arc<Type>,
tail_name: String,
next_tail_name: Option<String>,
complex_clause: bool,
},
WrapClause {
scope: Scope,
},
TupleClause {
scope: Scope,
tipo: Arc<Type>,
indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>,
subject_name: String,
count: usize,
complex_clause: bool,
},
ClauseGuard {
scope: Scope,
subject_name: String,
tipo: Arc<Type>,
},
ListClauseGuard {
scope: Scope,
tipo: Arc<Type>,
tail_name: String,
next_tail_name: Option<String>,
inverse: bool,
},
Finally {
scope: Scope,
},
// If
If {
scope: Scope,
tipo: Arc<Type>,
},
// Record Creation
Record {
scope: Scope,
tag: usize,
tipo: Arc<Type>,
count: usize,
},
RecordUpdate {
scope: Scope,
highest_index: usize,
indices: Vec<(usize, Arc<Type>)>,
tipo: Arc<Type>,
},
// Field Access
RecordAccess {
scope: Scope,
record_index: u64,
tipo: Arc<Type>,
},
FieldsExpose {
scope: Scope,
indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
},
// ListAccess
ListAccessor {
scope: Scope,
tipo: Arc<Type>,
names: Vec<String>,
tail: bool,
check_last_item: bool,
},
ListExpose {
scope: Scope,
tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
},
// Tuple Access
TupleAccessor {
scope: Scope,
names: Vec<String>,
tipo: Arc<Type>,
check_last_item: bool,
},
TupleIndex {
scope: Scope,
tipo: Arc<Type>,
tuple_index: usize,
},
// Misc.
ErrorTerm {
scope: Scope,
tipo: Arc<Type>,
},
Trace {
scope: Scope,
tipo: Arc<Type>,
},
NoOp {
scope: Scope,
},
FieldsEmpty {
scope: Scope,
},
ListEmpty {
scope: Scope,
},
}
impl Air {
pub fn scope(&self) -> Scope {
match self {
Air::Int { scope, .. }
| Air::String { scope, .. }
| Air::ByteArray { scope, .. }
| Air::Bool { scope, .. }
| Air::List { scope, .. }
| Air::Tuple { scope, .. }
| Air::Void { scope }
| Air::Var { scope, .. }
| Air::Call { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Fn { scope, .. }
| Air::Builtin { scope, .. }
| Air::BinOp { scope, .. }
| Air::UnOp { scope, .. }
| Air::Let { scope, .. }
| Air::UnWrapData { scope, .. }
| Air::WrapData { scope, .. }
| Air::AssertConstr { scope, .. }
| Air::AssertBool { scope, .. }
| Air::When { scope, .. }
| Air::Clause { scope, .. }
| Air::ListClause { scope, .. }
| Air::WrapClause { scope }
| Air::TupleClause { scope, .. }
| Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. }
| Air::Finally { scope }
| Air::If { scope, .. }
| Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. }
| Air::FieldsEmpty { scope }
| Air::ListEmpty { scope }
| Air::ListAccessor { scope, .. }
| Air::ListExpose { scope, .. }
| Air::TupleAccessor { scope, .. }
| Air::TupleIndex { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::Trace { scope, .. }
| Air::NoOp { scope, .. } => scope.clone(),
}
}
pub fn scope_mut(&mut self) -> &mut Scope {
match self {
Air::Int { scope, .. }
| Air::String { scope, .. }
| Air::ByteArray { scope, .. }
| Air::Bool { scope, .. }
| Air::List { scope, .. }
| Air::Tuple { scope, .. }
| Air::Void { scope }
| Air::Var { scope, .. }
| Air::Call { scope, .. }
| Air::DefineFunc { scope, .. }
| Air::Fn { scope, .. }
| Air::Builtin { scope, .. }
| Air::BinOp { scope, .. }
| Air::UnOp { scope, .. }
| Air::Let { scope, .. }
| Air::UnWrapData { scope, .. }
| Air::WrapData { scope, .. }
| Air::AssertConstr { scope, .. }
| Air::AssertBool { scope, .. }
| Air::When { scope, .. }
| Air::Clause { scope, .. }
| Air::ListClause { scope, .. }
| Air::WrapClause { scope }
| Air::TupleClause { scope, .. }
| Air::ClauseGuard { scope, .. }
| Air::ListClauseGuard { scope, .. }
| Air::Finally { scope }
| Air::If { scope, .. }
| Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. }
| Air::RecordAccess { scope, .. }
| Air::FieldsExpose { scope, .. }
| Air::FieldsEmpty { scope }
| Air::ListEmpty { scope }
| Air::ListAccessor { scope, .. }
| Air::ListExpose { scope, .. }
| Air::TupleAccessor { scope, .. }
| Air::TupleIndex { scope, .. }
| Air::ErrorTerm { scope, .. }
| Air::Trace { scope, .. }
| Air::NoOp { scope, .. } => scope,
}
}
pub fn tipo(&self) -> Option<Arc<Type>> {
match self {
Air::Int { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
Air::String { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "String".to_string(),
args: vec![],
}
.into(),
),
Air::ByteArray { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "ByteArray".to_string(),
args: vec![],
}
.into(),
),
Air::Bool { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
Air::Void { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Void".to_string(),
args: vec![],
}
.into(),
),
Air::WrapData { .. } => Some(
Type::App {
public: true,
module: String::new(),
name: "Data".to_string(),
args: vec![],
}
.into(),
),
Air::Var { constructor, .. } => Some(constructor.tipo.clone()),
Air::List { tipo, .. }
| Air::Tuple { tipo, .. }
| Air::Call { tipo, .. }
| Air::Builtin { tipo, .. }
| Air::BinOp { tipo, .. }
| Air::UnWrapData { tipo, .. }
| Air::When { tipo, .. }
| Air::Clause { tipo, .. }
| Air::ListClause { tipo, .. }
| Air::TupleClause { tipo, .. }
| Air::ClauseGuard { tipo, .. }
| Air::If { tipo, .. }
| Air::ListClauseGuard { tipo, .. }
| Air::Record { tipo, .. }
| Air::RecordUpdate { tipo, .. }
| Air::RecordAccess { tipo, .. }
| Air::ListAccessor { tipo, .. }
| Air::ListExpose { tipo, .. }
| Air::TupleAccessor { tipo, .. }
| Air::TupleIndex { tipo, .. }
| Air::ErrorTerm { tipo, .. }
| Air::Trace { tipo, .. } => Some(tipo.clone()),
Air::DefineFunc { .. }
| Air::Fn { .. }
| Air::Let { .. }
| Air::WrapClause { .. }
| Air::AssertConstr { .. }
| Air::AssertBool { .. }
| Air::Finally { .. }
| Air::FieldsExpose { .. }
| Air::FieldsEmpty { .. }
| Air::ListEmpty { .. }
| Air::NoOp { .. } => None,
Air::UnOp { op, .. } => match op {
UnOp::Not => Some(
Type::App {
public: true,
module: String::new(),
name: "Bool".to_string(),
args: vec![],
}
.into(),
),
UnOp::Negate => Some(
Type::App {
public: true,
module: String::new(),
name: "Int".to_string(),
args: vec![],
}
.into(),
),
},
}
}
}

View File

@ -0,0 +1 @@

View File

@ -8,7 +8,6 @@ pub mod builtins;
pub mod expr; pub mod expr;
pub mod format; pub mod format;
pub mod gen_uplc; pub mod gen_uplc;
pub mod gen_uplc2;
pub mod levenshtein; pub mod levenshtein;
pub mod parser; pub mod parser;
pub mod pretty; pub mod pretty;

View File

@ -317,7 +317,6 @@ impl CheckedModules {
FunctionAccessKey { FunctionAccessKey {
module_name: module.name.clone(), module_name: module.name.clone(),
function_name: func.name.clone(), function_name: func.name.clone(),
variant_name: String::new(),
}, },
func, func,
); );