Skip to content

Commit

Permalink
Cleanup implementation from multi-subjects when/is
Browse files Browse the repository at this point in the history
  • Loading branch information
KtorZ committed Mar 17, 2023
1 parent c113582 commit 28a3844
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 371 deletions.
51 changes: 14 additions & 37 deletions crates/aiken-lang/src/ast.rs
@@ -1,5 +1,3 @@
use std::{fmt, ops::Range, sync::Arc};

use crate::{
builtins::{self, bool},
expr::{TypedExpr, UntypedExpr},
Expand All @@ -8,6 +6,8 @@ use crate::{
};
use miette::Diagnostic;
use owo_colors::{OwoColorize, Stream::Stdout};
use std::{fmt, ops::Range, sync::Arc};
use vec1::Vec1;

pub const ASSERT_VARIABLE: &str = "_try";
pub const CAPTURE_VARIABLE: &str = "_capture";
Expand Down Expand Up @@ -909,56 +909,33 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
pub type UntypedMultiPattern = MultiPattern<(), ()>;
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;

pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>;
pub type UntypedClause = Clause<UntypedExpr, (), ()>;
#[derive(Debug, Clone, PartialEq)]
pub struct UntypedClause {
pub location: Span,
pub patterns: Vec1<Pattern<(), ()>>,
pub guard: Option<ClauseGuard<()>>,
pub then: UntypedExpr,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Clause<Expr, PatternConstructor, Type> {
pub struct TypedClause {
pub location: Span,
pub pattern: MultiPattern<PatternConstructor, Type>,
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
pub guard: Option<ClauseGuard<Type>>,
pub then: Expr,
pub pattern: Pattern<PatternConstructor, Arc<Type>>,
pub guard: Option<ClauseGuard<Arc<Type>>>,
pub then: TypedExpr,
}

impl TypedClause {
pub fn location(&self) -> Span {
Span {
start: self
.pattern
.get(0)
.map(|p| p.location().start)
.unwrap_or_default(),
start: self.pattern.location().start,
end: self.then.location().end,
}
}

pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
self.then.find_node(byte_index)
}

pub fn desugarize(self) -> Vec<Self> {
let mut alternative_patterns = self
.alternative_patterns
.into_iter()
.map(|pattern| Self {
location: self.location,
pattern,
alternative_patterns: vec![],
guard: self.guard.clone(),
then: self.then.clone(),
})
.collect::<Vec<_>>();

let mut clauses = vec![Self {
alternative_patterns: vec![],
..self
}];

clauses.append(&mut alternative_patterns);

clauses
}
}

pub type UntypedClauseGuard = ClauseGuard<()>;
Expand Down
41 changes: 18 additions & 23 deletions crates/aiken-lang/src/builder.rs
Expand Up @@ -18,8 +18,8 @@ use uplc::{
use crate::{
air::Air,
ast::{
AssignmentKind, BinOp, Clause, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg,
TypedDataType, UnOp,
AssignmentKind, BinOp, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg,
TypedClause, TypedDataType, UnOp,
},
expr::TypedExpr,
tipo::{PatternConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant},
Expand Down Expand Up @@ -396,21 +396,19 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
}
}

pub fn rearrange_clauses(
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
let mut sorted_clauses = clauses;

// if we have a list sort clauses so we can plug holes for cases not covered by clauses
// TODO: while having 10000000 element list is impossible to destructure in plutus budget,
// let's sort clauses by a safer manner
// TODO: how shall tails be weighted? Since any clause after will not run
sorted_clauses.sort_by(|clause1, clause2| {
let clause1_len = match &clause1.pattern[0] {
let clause1_len = match &clause1.pattern {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 10000000,
};
let clause2_len = match &clause2.pattern[0] {
let clause2_len = match &clause2.pattern {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 10000001,
};
Expand All @@ -427,7 +425,7 @@ pub fn rearrange_clauses(

// If we have a catch all, use that. Otherwise use todo which will result in error
// TODO: fill in todo label with description
let plug_in_then = match &sorted_clauses[sorted_clauses.len() - 1].pattern[0] {
let plug_in_then = match &sorted_clauses[sorted_clauses.len() - 1].pattern {
Pattern::Var { name, .. } => {
assign_plug_in_name = Some(name);
sorted_clauses[sorted_clauses.len() - 1].clone().then
Expand All @@ -452,7 +450,7 @@ pub fn rearrange_clauses(
};

for (index, clause) in sorted_clauses.iter().enumerate() {
if let Pattern::List { elements, .. } = &clause.pattern[0] {
if let Pattern::List { elements, .. } = &clause.pattern {
// found a hole and now we plug it
while elems_len < elements.len() {
let mut discard_elems = vec![];
Expand All @@ -466,9 +464,9 @@ pub fn rearrange_clauses(

// If we have a named catch all then in scope the name and create list of discards, otherwise list of discards
let clause_to_fill = if let Some(name) = assign_plug_in_name {
Clause {
TypedClause {
location: Span::empty(),
pattern: vec![Pattern::Assign {
pattern: Pattern::Assign {
name: name.clone(),
location: Span::empty(),
pattern: Pattern::List {
Expand All @@ -477,20 +475,18 @@ pub fn rearrange_clauses(
tail: None,
}
.into(),
}],
alternative_patterns: vec![],
},
guard: None,
then: plug_in_then.clone(),
}
} else {
Clause {
TypedClause {
location: Span::empty(),
pattern: vec![Pattern::List {
pattern: Pattern::List {
location: Span::empty(),
elements: discard_elems,
tail: None,
}],
alternative_patterns: vec![],
},
guard: None,
then: plug_in_then.clone(),
}
Expand All @@ -502,7 +498,7 @@ pub fn rearrange_clauses(
}

// if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses
match &clause.pattern[0] {
match &clause.pattern {
Pattern::Var { .. } => {
last_clause_index = index + 1;
last_clause_set = true;
Expand Down Expand Up @@ -533,14 +529,13 @@ pub fn rearrange_clauses(

// If the last condition doesn't have a catch all or tail then add a catch all with a todo
if index == sorted_clauses.len() - 1 {
if let Pattern::List { tail: None, .. } = &clause.pattern[0] {
final_clauses.push(Clause {
if let Pattern::List { tail: None, .. } = &clause.pattern {
final_clauses.push(TypedClause {
location: Span::empty(),
pattern: vec![Pattern::Discard {
pattern: Pattern::Discard {
name: "_".to_string(),
location: Span::empty(),
}],
alternative_patterns: vec![],
},
guard: None,
then: plug_in_then.clone(),
});
Expand Down
21 changes: 10 additions & 11 deletions crates/aiken-lang/src/expr.rs
Expand Up @@ -4,9 +4,9 @@ use vec1::Vec1;

use crate::{
ast::{
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Clause,
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind,
TypedRecordUpdateArg, UnOp, UntypedRecordUpdateArg,
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, TypedClause,
TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg,
},
builtins::void,
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
Expand Down Expand Up @@ -102,8 +102,8 @@ pub enum TypedExpr {
When {
location: Span,
tipo: Arc<Type>,
subjects: Vec<Self>,
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>>>,
subject: Box<Self>,
clauses: Vec<TypedClause>,
},

If {
Expand Down Expand Up @@ -355,10 +355,9 @@ impl TypedExpr {
TypedExpr::Assignment { value, .. } => value.find_node(byte_index),

TypedExpr::When {
subjects, clauses, ..
} => subjects
.iter()
.find_map(|subject| subject.find_node(byte_index))
subject, clauses, ..
} => subject
.find_node(byte_index)
.or_else(|| {
clauses
.iter()
Expand Down Expand Up @@ -481,8 +480,8 @@ pub enum UntypedExpr {

When {
location: Span,
subjects: Vec<Self>,
clauses: Vec<Clause<Self, (), ()>>,
subject: Box<Self>,
clauses: Vec<UntypedClause>,
},

If {
Expand Down
15 changes: 5 additions & 10 deletions crates/aiken-lang/src/format.rs
Expand Up @@ -728,8 +728,8 @@ impl<'comments> Formatter<'comments> {
} => self.trace(kind, text, then),

UntypedExpr::When {
subjects, clauses, ..
} => self.when(subjects, clauses),
subject, clauses, ..
} => self.when(subject, clauses),

UntypedExpr::FieldAccess {
label, container, ..
Expand Down Expand Up @@ -933,14 +933,11 @@ impl<'comments> Formatter<'comments> {

pub fn when<'a>(
&mut self,
subjects: &'a [UntypedExpr],
subject: &'a UntypedExpr,
clauses: &'a [UntypedClause],
) -> Document<'a> {
let subjects_doc = break_("when", "when ")
.append(join(
subjects.iter().map(|s| self.wrap_expr(s)),
break_(",", ", "),
))
.append(self.wrap_expr(subject))
.nest(INDENT)
.append(break_("", " "))
.append("is {")
Expand Down Expand Up @@ -1449,9 +1446,7 @@ impl<'comments> Formatter<'comments> {
let space_before = self.pop_empty_lines(clause.location.start);
let after_position = clause.location.end;
let clause_doc = join(
std::iter::once(&clause.pattern)
.chain(&clause.alternative_patterns)
.map(|p| join(p.iter().map(|p| self.pattern(p)), ", ".to_doc())),
clause.patterns.iter().map(|p| self.pattern(p)),
" | ".to_doc(),
);
let clause_doc = match &clause.guard {
Expand Down
29 changes: 15 additions & 14 deletions crates/aiken-lang/src/parser.rs
@@ -1,6 +1,3 @@
use chumsky::prelude::*;
use vec1::Vec1;

pub mod error;
pub mod extra;
pub mod lexer;
Expand All @@ -13,10 +10,11 @@ use crate::{
},
expr,
};

use chumsky::prelude::*;
use error::ParseError;
use extra::ModuleExtra;
use token::Token;
use vec1::{vec1, Vec1};

pub fn module(
src: &str,
Expand Down Expand Up @@ -923,7 +921,7 @@ pub fn expr_parser(
let when_clause_parser = pattern_parser()
.then(
just(Token::Vbar)
.ignore_then(pattern_parser().map(|pattern| vec![pattern]))
.ignore_then(pattern_parser())
.repeated()
.or_not(),
)
Expand Down Expand Up @@ -962,26 +960,29 @@ pub fn expr_parser(
}),
)))
.map_with_span(
|(((pattern, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
location: span,
pattern: vec![pattern],
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
guard,
then,
|(((pattern, alternative_patterns_opt), guard), then), span| {
let mut patterns = vec1![pattern];
patterns.append(&mut alternative_patterns_opt.unwrap_or_default());
ast::UntypedClause {
location: span,
patterns,
guard,
then,
}
},
);

let when_parser = just(Token::When)
// TODO: If subject is empty we should return ParseErrorType::ExpectedExpr,
.ignore_then(r.clone().separated_by(just(Token::Comma)))
.ignore_then(r.clone().map(Box::new))
.then_ignore(just(Token::Is))
.then_ignore(just(Token::LeftBrace))
// TODO: If clauses are empty we should return ParseErrorType::NoCaseClause
.then(when_clause_parser.repeated())
.then_ignore(just(Token::RightBrace))
.map_with_span(|(subjects, clauses), span| expr::UntypedExpr::When {
.map_with_span(|(subject, clauses), span| expr::UntypedExpr::When {
location: span,
subjects,
subject,
clauses,
});

Expand Down

0 comments on commit 28a3844

Please sign in to comment.