feat: add trace

This commit is contained in:
rvcas 2022-12-21 14:21:13 -05:00 committed by Lucas
parent 9068c89c00
commit 429126e38f
45 changed files with 315 additions and 23 deletions

View File

@ -203,6 +203,12 @@ pub enum Air {
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
Trace {
scope: Vec<u64>,
text: Option<String>,
tipo: Arc<Type>,
},
Record { Record {
scope: Vec<u64>, scope: Vec<u64>,
}, },
@ -261,6 +267,7 @@ impl Air {
| Air::Record { scope, .. } | Air::Record { scope, .. }
| Air::RecordUpdate { scope, .. } | Air::RecordUpdate { scope, .. }
| Air::Negate { scope, .. } | Air::Negate { scope, .. }
| Air::Trace { scope, .. }
| Air::TupleAccessor { scope, .. } => scope.to_vec(), | Air::TupleAccessor { scope, .. } => scope.to_vec(),
} }
} }

View File

@ -344,13 +344,7 @@ pub fn from_default_function(
Some((tipo, 3)) Some((tipo, 3))
} }
DefaultFunction::ChooseUnit => None, DefaultFunction::ChooseUnit => None,
DefaultFunction::Trace => { DefaultFunction::Trace => None,
let ret = generic_var(id_gen.next());
let tipo = function(vec![string(), ret.clone()], ret);
Some((tipo, 2))
}
DefaultFunction::FstPair => None, DefaultFunction::FstPair => None,
DefaultFunction::SndPair => None, DefaultFunction::SndPair => None,
DefaultFunction::ChooseList => None, DefaultFunction::ChooseList => None,

View File

@ -91,6 +91,13 @@ pub enum TypedExpr {
kind: AssignmentKind, kind: AssignmentKind,
}, },
Trace {
location: Span,
tipo: Arc<Type>,
then: Box<Self>,
text: Option<String>,
},
When { When {
location: Span, location: Span,
tipo: Arc<Type>, tipo: Arc<Type>,
@ -158,6 +165,7 @@ impl TypedExpr {
match self { match self {
Self::Negate { .. } => bool(), Self::Negate { .. } => bool(),
Self::Var { constructor, .. } => constructor.tipo.clone(), Self::Var { constructor, .. } => constructor.tipo.clone(),
Self::Trace {then, ..} => then.tipo(),
Self::Fn { tipo, .. } Self::Fn { tipo, .. }
| Self::Int { tipo, .. } | Self::Int { tipo, .. }
| Self::Todo { tipo, .. } | Self::Todo { tipo, .. }
@ -200,6 +208,7 @@ impl TypedExpr {
match self { match self {
TypedExpr::Fn { .. } TypedExpr::Fn { .. }
| TypedExpr::Int { .. } | TypedExpr::Int { .. }
| TypedExpr::Trace { .. }
| TypedExpr::List { .. } | TypedExpr::List { .. }
| TypedExpr::Call { .. } | TypedExpr::Call { .. }
| TypedExpr::When { .. } | TypedExpr::When { .. }
@ -240,6 +249,7 @@ impl TypedExpr {
Self::Fn { location, .. } Self::Fn { location, .. }
| Self::Int { location, .. } | Self::Int { location, .. }
| Self::Var { location, .. } | Self::Var { location, .. }
| Self::Trace { location, .. }
| Self::Todo { location, .. } | Self::Todo { location, .. }
| Self::When { location, .. } | Self::When { location, .. }
| Self::Call { location, .. } | Self::Call { location, .. }
@ -276,6 +286,7 @@ impl TypedExpr {
match self { match self {
Self::Fn { location, .. } Self::Fn { location, .. }
| Self::Int { location, .. } | Self::Int { location, .. }
| Self::Trace { location, .. }
| Self::Var { location, .. } | Self::Var { location, .. }
| Self::Todo { location, .. } | Self::Todo { location, .. }
| Self::When { location, .. } | Self::When { location, .. }
@ -363,7 +374,11 @@ pub enum UntypedExpr {
kind: AssignmentKind, kind: AssignmentKind,
annotation: Option<Annotation>, annotation: Option<Annotation>,
}, },
Trace {
location: Span,
then: Box<Self>,
text: Option<String>,
},
When { When {
location: Span, location: Span,
subjects: Vec<Self>, subjects: Vec<Self>,
@ -462,6 +477,7 @@ impl UntypedExpr {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
match self { match self {
Self::PipeLine { expressions, .. } => expressions.last().location(), Self::PipeLine { expressions, .. } => expressions.last().location(),
Self::Trace { then, .. } => then.location(),
Self::Fn { location, .. } Self::Fn { location, .. }
| Self::Var { location, .. } | Self::Var { location, .. }
| Self::Int { location, .. } | Self::Int { location, .. }
@ -498,7 +514,7 @@ impl UntypedExpr {
.map(|e| e.start_byte_index()) .map(|e| e.start_byte_index())
.unwrap_or(location.start), .unwrap_or(location.start),
Self::PipeLine { expressions, .. } => expressions.first().start_byte_index(), Self::PipeLine { expressions, .. } => expressions.first().start_byte_index(),
Self::Assignment { location, .. } => location.start, Self::Trace { location, .. } | Self::Assignment { location, .. } => location.start,
_ => self.location().start, _ => self.location().start,
} }
} }

View File

@ -751,6 +751,29 @@ impl<'comments> Formatter<'comments> {
.. ..
} => self.assignment(pattern, value, None, Some(*kind), annotation), } => self.assignment(pattern, value, None, Some(*kind), annotation),
UntypedExpr::Trace {
text: None, then, ..
} => "trace"
.to_doc()
.append(if self.pop_empty_lines(then.start_byte_index()) {
lines(2)
} else {
line()
})
.append(self.expr(then)),
UntypedExpr::Trace {
text: Some(l),
then,
..
} => docvec!["trace(\"", l, "\")"]
.append(if self.pop_empty_lines(then.start_byte_index()) {
lines(2)
} else {
line()
})
.append(self.expr(then)),
UntypedExpr::When { UntypedExpr::When {
subjects, clauses, .. subjects, clauses, ..
} => self.when(subjects, clauses), } => self.when(subjects, clauses),
@ -1319,7 +1342,9 @@ impl<'comments> Formatter<'comments> {
fn wrap_expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> { fn wrap_expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
match expr { match expr {
UntypedExpr::Sequence { .. } | UntypedExpr::Assignment { .. } => "{" UntypedExpr::Trace { .. }
| UntypedExpr::Sequence { .. }
| UntypedExpr::Assignment { .. } => "{"
.to_doc() .to_doc()
.append(line().append(self.expr(expr)).nest(INDENT)) .append(line().append(self.expr(expr)).nest(INDENT))
.append(line()) .append(line())
@ -1356,7 +1381,9 @@ impl<'comments> Formatter<'comments> {
fn case_clause_value<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> { fn case_clause_value<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
match expr { match expr {
UntypedExpr::Sequence { .. } | UntypedExpr::Assignment { .. } => " {" UntypedExpr::Trace { .. }
| UntypedExpr::Sequence { .. }
| UntypedExpr::Assignment { .. } => " {"
.to_doc() .to_doc()
.append(line().append(self.expr(expr)).nest(INDENT).group()) .append(line().append(self.expr(expr)).nest(INDENT).group())
.append(line()) .append(line())

View File

@ -553,9 +553,23 @@ pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = Par
pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> { pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
recursive(|r| { recursive(|r| {
choice((
just(Token::Trace)
.ignore_then(
select! {Token::String {value} => value}
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.or_not(),
)
.then(r.clone())
.map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
location: span,
then: Box::new(then_),
text,
}),
expr_parser(r.clone()) expr_parser(r.clone())
.then(r.repeated()) .then(r.repeated())
.foldl(|current, next| current.append_in_sequence(next)) .foldl(|current, next| current.append_in_sequence(next)),
))
}) })
} }

View File

@ -73,6 +73,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
.labelled("string"); .labelled("string");
let keyword = text::ident().map(|s: String| match s.as_str() { let keyword = text::ident().map(|s: String| match s.as_str() {
"trace" => Token::Trace,
"as" => Token::As, "as" => Token::As,
"assert" => Token::Assert, "assert" => Token::Assert,
"check" => Token::Assert, "check" => Token::Assert,

View File

@ -73,6 +73,7 @@ pub enum Token {
Todo, Todo,
Type, Type,
When, When,
Trace,
} }
impl fmt::Display for Token { impl fmt::Display for Token {
@ -144,6 +145,7 @@ impl fmt::Display for Token {
Token::Opaque => "opaque", Token::Opaque => "opaque",
Token::Pub => "pub", Token::Pub => "pub",
Token::Todo => "todo", Token::Todo => "todo",
Token::Trace => "trace",
Token::Type => "type", Token::Type => "type",
Token::Test => "test", Token::Test => "test",
}; };

View File

@ -279,6 +279,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
.. ..
} => self.infer_assignment(pattern, *value, kind, &annotation, location), } => self.infer_assignment(pattern, *value, kind, &annotation, location),
UntypedExpr::Trace {
location,
then,
text,
} => self.infer_trace(*then, location, text),
UntypedExpr::When { UntypedExpr::When {
location, location,
subjects, subjects,
@ -1711,6 +1717,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
} }
} }
fn infer_trace(
&mut self,
then: UntypedExpr,
location: Span,
text: Option<String>,
) -> Result<TypedExpr, Error> {
let then = self.infer(then)?;
let tipo = then.tipo();
Ok(TypedExpr::Trace {
location,
tipo,
then: Box::new(then),
text,
})
}
fn infer_value_constructor( fn infer_value_constructor(
&mut self, &mut self,
module: &Option<String>, module: &Option<String>,

View File

@ -475,6 +475,7 @@ fn str_to_keyword(word: &str) -> Option<Token> {
"pub" => Some(Token::Pub), "pub" => Some(Token::Pub),
"todo" => Some(Token::Todo), "todo" => Some(Token::Todo),
"type" => Some(Token::Type), "type" => Some(Token::Type),
"trace" => Some(Token::Trace),
_ => None, _ => None,
} }
} }

View File

@ -517,6 +517,21 @@ impl<'a> CodeGenerator<'a> {
ir_stack.append(&mut elems_air); ir_stack.append(&mut elems_air);
} }
TypedExpr::Trace {
tipo, then, text, ..
} => {
let mut scope = scope;
ir_stack.push(Air::Trace {
text: text.clone(),
tipo: tipo.clone(),
scope: scope.clone(),
});
scope.push(self.id_gen.next());
self.build_ir(then, ir_stack, scope);
}
} }
} }
@ -3517,8 +3532,20 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
} }
Air::Todo { .. } => { Air::Todo { label, .. } => {
arg_stack.push(Term::Error); let term = Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::Trace).force_wrap().into(),
argument: Term::Constant(uplc::ast::Constant::String(
label.unwrap_or_else(|| "aiken::todo".to_string()),
))
.into(),
}
.into(),
argument: Term::Error.into(),
};
arg_stack.push(term);
} }
Air::Record { .. } => todo!(), Air::Record { .. } => todo!(),
Air::RecordUpdate { .. } => todo!(), Air::RecordUpdate { .. } => todo!(),
@ -3677,6 +3704,23 @@ impl<'a> CodeGenerator<'a> {
}; };
} }
arg_stack.push(term);
}
Air::Trace { text, .. } => {
let term = arg_stack.pop().unwrap();
let term = Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::Trace).force_wrap().into(),
argument: Term::Constant(uplc::ast::Constant::String(
text.unwrap_or_else(|| "aike::trace".to_string()),
))
.into(),
}
.into(),
argument: term.into(),
};
arg_stack.push(term); arg_stack.push(term);
} }
} }

1
examples/acceptance_tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -1,2 +1,2 @@
name = "acceptance_test_032" name = "aiken-lang/acceptance_test_032"
version = "0.0.0" version = "0.0.0"

View File

@ -1,14 +1,15 @@
use aiken/builtin fn is_negative(i: Int) -> Bool {
fn is_negative(i : Int) -> Bool {
if i < 0 { if i < 0 {
builtin.trace("is negative", True) trace("is negative")
True
} else { } else {
builtin.trace("is non-negative", False) trace("is non-negative")
False
} }
} }
test trace_1() { test trace_1() {
is_negative(-14) && !is_negative(42) is_negative(-14) && !is_negative(42)
} }