Merge branch 'aiken-watch'
This commit is contained in:
commit
c2725abcea
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,6 +1,20 @@
|
|||
# Changelog
|
||||
|
||||
## v1.0.20-alpha - 10/25/2023
|
||||
## v1.0.21-alpha - unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: `--watch` flag on the `build`, `check` and `docs` commands to automatically watch and re-execute the command on file changes.
|
||||
|
||||
### Changed
|
||||
|
||||
N/A
|
||||
|
||||
### Fixed
|
||||
|
||||
N/A
|
||||
|
||||
## v1.0.20-alpha - 2023-10-25
|
||||
|
||||
### Added
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"miette",
|
||||
"minicbor",
|
||||
"notify",
|
||||
"owo-colors",
|
||||
"pallas",
|
||||
"pallas-traverse",
|
||||
|
@ -360,6 +361,12 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
@ -505,7 +512,7 @@ checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
|
|||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size 0.2.6",
|
||||
|
@ -662,7 +669,7 @@ version = "0.25.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
|
@ -866,6 +873,18 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
|
@ -921,6 +940,15 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fslock"
|
||||
version = "0.2.1"
|
||||
|
@ -1054,7 +1082,7 @@ version = "0.17.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
|
@ -1293,13 +1321,33 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inquire"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33e7c1ddeb15c9abcbfef6029d8e29f69b52b6d6c891031b88ed91b5065803b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"crossterm",
|
||||
"dyn-clone",
|
||||
"lazy_static",
|
||||
|
@ -1414,6 +1462,26 @@ dependencies = [
|
|||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1505,7 +1573,7 @@ version = "0.94.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
|
@ -1660,6 +1728,25 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "6.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
|
@ -1728,7 +1815,7 @@ version = "0.10.55"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -2069,7 +2156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
|
@ -2097,7 +2184,7 @@ version = "0.9.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
@ -2184,7 +2271,7 @@ version = "0.2.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2193,7 +2280,7 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2283,7 +2370,7 @@ version = "0.37.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
|
@ -2377,7 +2464,7 @@ version = "2.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
|
|
|
@ -516,7 +516,7 @@ impl<'comments> Formatter<'comments> {
|
|||
.group();
|
||||
|
||||
// Format body
|
||||
let body = self.expr(body);
|
||||
let body = self.expr(body, true);
|
||||
|
||||
// Add any trailing comments
|
||||
let body = match printed_comments(self.pop_comments(end_location), false) {
|
||||
|
@ -609,8 +609,10 @@ impl<'comments> Formatter<'comments> {
|
|||
) -> Document<'a> {
|
||||
let args = wrap_args(args.iter().map(|e| (self.fn_arg(e), false))).group();
|
||||
let body = match body {
|
||||
UntypedExpr::Trace { .. } | UntypedExpr::When { .. } => self.expr(body).force_break(),
|
||||
_ => self.expr(body),
|
||||
UntypedExpr::Trace { .. } | UntypedExpr::When { .. } => {
|
||||
self.expr(body, true).force_break()
|
||||
}
|
||||
_ => self.expr(body, true),
|
||||
};
|
||||
|
||||
let header = "fn".to_doc().append(args);
|
||||
|
@ -634,15 +636,19 @@ impl<'comments> Formatter<'comments> {
|
|||
fn sequence<'a>(&mut self, expressions: &'a [UntypedExpr]) -> Document<'a> {
|
||||
let count = expressions.len();
|
||||
let mut documents = Vec::with_capacity(count * 2);
|
||||
|
||||
for (i, expression) in expressions.iter().enumerate() {
|
||||
let preceding_newline = self.pop_empty_lines(expression.start_byte_index());
|
||||
|
||||
if i != 0 && preceding_newline {
|
||||
documents.push(lines(2));
|
||||
} else if i != 0 {
|
||||
documents.push(lines(1));
|
||||
}
|
||||
documents.push(self.expr(expression).group());
|
||||
|
||||
documents.push(self.expr(expression, false).group());
|
||||
}
|
||||
|
||||
documents.to_doc().force_break()
|
||||
}
|
||||
|
||||
|
@ -653,8 +659,6 @@ impl<'comments> Formatter<'comments> {
|
|||
kind: AssignmentKind,
|
||||
annotation: &'a Option<Annotation>,
|
||||
) -> Document<'a> {
|
||||
self.pop_empty_lines(pattern.location().end);
|
||||
|
||||
let keyword = match kind {
|
||||
AssignmentKind::Let => "let",
|
||||
AssignmentKind::Expect => "expect",
|
||||
|
@ -667,6 +671,8 @@ impl<'comments> Formatter<'comments> {
|
|||
keyword.to_doc().append(self.case_clause_value(value))
|
||||
}
|
||||
_ => {
|
||||
self.pop_empty_lines(pattern.location().end);
|
||||
|
||||
let pattern = self.pattern(pattern);
|
||||
|
||||
let annotation = annotation
|
||||
|
@ -782,7 +788,7 @@ impl<'comments> Formatter<'comments> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
|
||||
pub fn expr<'a>(&mut self, expr: &'a UntypedExpr, is_top_level: bool) -> Document<'a> {
|
||||
let comments = self.pop_comments(expr.start_byte_index());
|
||||
|
||||
let document = match expr {
|
||||
|
@ -821,7 +827,18 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
UntypedExpr::String { value, .. } => self.string(value),
|
||||
|
||||
UntypedExpr::Sequence { expressions, .. } => self.sequence(expressions),
|
||||
UntypedExpr::Sequence { expressions, .. } => {
|
||||
let sequence = self.sequence(expressions);
|
||||
|
||||
if is_top_level {
|
||||
sequence
|
||||
} else {
|
||||
"{".to_doc()
|
||||
.append(line().append(sequence).nest(INDENT).group())
|
||||
.append(line())
|
||||
.append("}")
|
||||
}
|
||||
}
|
||||
|
||||
UntypedExpr::Var { name, .. } if name.contains(CAPTURE_VARIABLE) => "_".to_doc(),
|
||||
|
||||
|
@ -878,7 +895,10 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
UntypedExpr::FieldAccess {
|
||||
label, container, ..
|
||||
} => self.expr(container).append(".").append(label.as_str()),
|
||||
} => self
|
||||
.expr(container, false)
|
||||
.append(".")
|
||||
.append(label.as_str()),
|
||||
|
||||
UntypedExpr::RecordUpdate {
|
||||
constructor,
|
||||
|
@ -893,7 +913,7 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
UntypedExpr::TupleIndex { index, tuple, .. } => {
|
||||
let suffix = Ordinal(*index + 1).suffix().to_doc();
|
||||
self.expr(tuple)
|
||||
self.expr(tuple, false)
|
||||
.append(".".to_doc())
|
||||
.append((index + 1).to_doc())
|
||||
.append(suffix)
|
||||
|
@ -953,7 +973,7 @@ impl<'comments> Formatter<'comments> {
|
|||
} else {
|
||||
line()
|
||||
})
|
||||
.append(self.expr(then)),
|
||||
.append(self.expr(then, false)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1027,7 +1047,7 @@ impl<'comments> Formatter<'comments> {
|
|||
false
|
||||
};
|
||||
|
||||
self.expr(fun)
|
||||
self.expr(fun, false)
|
||||
.append(wrap_args(
|
||||
args.iter()
|
||||
.map(|a| (self.call_arg(a, needs_curly), needs_curly)),
|
||||
|
@ -1051,7 +1071,7 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
let else_begin = line().append("} else {");
|
||||
|
||||
let else_body = line().append(self.expr(final_else)).nest(INDENT);
|
||||
let else_body = line().append(self.expr(final_else, true)).nest(INDENT);
|
||||
|
||||
let else_end = line().append("}");
|
||||
|
||||
|
@ -1072,7 +1092,7 @@ impl<'comments> Formatter<'comments> {
|
|||
.append(break_("{", " {"))
|
||||
.group();
|
||||
|
||||
let if_body = line().append(self.expr(&branch.body)).nest(INDENT);
|
||||
let if_body = line().append(self.expr(&branch.body, true)).nest(INDENT);
|
||||
|
||||
if_begin.append(if_body)
|
||||
}
|
||||
|
@ -1110,8 +1130,8 @@ impl<'comments> Formatter<'comments> {
|
|||
args: &'a [UntypedRecordUpdateArg],
|
||||
) -> Document<'a> {
|
||||
use std::iter::once;
|
||||
let constructor_doc = self.expr(constructor);
|
||||
let spread_doc = "..".to_doc().append(self.expr(&spread.base));
|
||||
let constructor_doc = self.expr(constructor, false);
|
||||
let spread_doc = "..".to_doc().append(self.expr(&spread.base, false));
|
||||
let arg_docs = args.iter().map(|a| (self.record_update_arg(a), true));
|
||||
let all_arg_docs = once((spread_doc, true)).chain(arg_docs);
|
||||
constructor_doc.append(wrap_args(all_arg_docs)).group()
|
||||
|
@ -1128,14 +1148,14 @@ impl<'comments> Formatter<'comments> {
|
|||
let left_precedence = left.binop_precedence();
|
||||
let right_precedence = right.binop_precedence();
|
||||
|
||||
let left = self.expr(left);
|
||||
let right = self.expr(right);
|
||||
let left = self.expr(left, false);
|
||||
let right = self.expr(right, false);
|
||||
|
||||
self.operator_side(left, precedence, left_precedence)
|
||||
.append(" ")
|
||||
.append(name)
|
||||
.append(" ")
|
||||
.append(self.operator_side(right, precedence, right_precedence - 1))
|
||||
.append(self.operator_side(right, precedence, right_precedence.saturating_sub(1)))
|
||||
}
|
||||
|
||||
pub fn operator_side<'a>(&mut self, doc: Document<'a>, op: u8, side: u8) -> Document<'a> {
|
||||
|
@ -1161,7 +1181,9 @@ impl<'comments> Formatter<'comments> {
|
|||
.append(
|
||||
line()
|
||||
.append(join(
|
||||
expressions.iter().map(|expression| self.expr(expression)),
|
||||
expressions
|
||||
.iter()
|
||||
.map(|expression| self.expr(expression, false)),
|
||||
",".to_doc().append(line()),
|
||||
))
|
||||
.nest(INDENT)
|
||||
|
@ -1241,10 +1263,10 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
if hole_in_first_position && args.len() == 1 {
|
||||
// x |> fun(_)
|
||||
self.expr(fun)
|
||||
self.expr(fun, false)
|
||||
} else if hole_in_first_position {
|
||||
// x |> fun(_, 2, 3)
|
||||
self.expr(fun).append(
|
||||
self.expr(fun, false).append(
|
||||
wrap_args(
|
||||
args.iter()
|
||||
.skip(1)
|
||||
|
@ -1254,7 +1276,7 @@ impl<'comments> Formatter<'comments> {
|
|||
)
|
||||
} else {
|
||||
// x |> fun(1, _, 3)
|
||||
self.expr(fun)
|
||||
self.expr(fun, false)
|
||||
.append(wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group())
|
||||
}
|
||||
}
|
||||
|
@ -1267,14 +1289,14 @@ impl<'comments> Formatter<'comments> {
|
|||
..
|
||||
} => match args.as_slice() {
|
||||
[first, second] if is_breakable_expr(&second.value) && first.is_capture_hole() => {
|
||||
self.expr(fun)
|
||||
self.expr(fun, false)
|
||||
.append("(_, ")
|
||||
.append(self.call_arg(second, false))
|
||||
.append(")")
|
||||
.group()
|
||||
}
|
||||
|
||||
_ => self.expr(fun).append(
|
||||
_ => self.expr(fun, false).append(
|
||||
wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group(),
|
||||
),
|
||||
},
|
||||
|
@ -1556,12 +1578,12 @@ impl<'comments> Formatter<'comments> {
|
|||
| UntypedExpr::Sequence { .. }
|
||||
| UntypedExpr::Assignment { .. } => "{"
|
||||
.to_doc()
|
||||
.append(line().append(self.expr(expr)).nest(INDENT))
|
||||
.append(line().append(self.expr(expr, true)).nest(INDENT))
|
||||
.append(line())
|
||||
.append("}")
|
||||
.force_break(),
|
||||
|
||||
_ => self.expr(expr),
|
||||
_ => self.expr(expr, false),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1598,18 +1620,21 @@ impl<'comments> Formatter<'comments> {
|
|||
| UntypedExpr::Sequence { .. }
|
||||
| UntypedExpr::Assignment { .. } => " {"
|
||||
.to_doc()
|
||||
.append(line().append(self.expr(expr)).nest(INDENT).group())
|
||||
.append(line().append(self.expr(expr, true)).nest(INDENT).group())
|
||||
.append(line())
|
||||
.append("}")
|
||||
.force_break(),
|
||||
|
||||
UntypedExpr::Fn { .. } | UntypedExpr::List { .. } => {
|
||||
line().append(self.expr(expr)).nest(INDENT).group()
|
||||
line().append(self.expr(expr, false)).nest(INDENT).group()
|
||||
}
|
||||
|
||||
UntypedExpr::When { .. } => line().append(self.expr(expr)).nest(INDENT).group(),
|
||||
UntypedExpr::When { .. } => line().append(self.expr(expr, false)).nest(INDENT).group(),
|
||||
|
||||
_ => break_("", " ").append(self.expr(expr)).nest(INDENT).group(),
|
||||
_ => break_("", " ")
|
||||
.append(self.expr(expr, false))
|
||||
.nest(INDENT)
|
||||
.group(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1647,7 +1672,7 @@ impl<'comments> Formatter<'comments> {
|
|||
|| break_(",", ", ")
|
||||
};
|
||||
let elements_document = join(elements.iter().map(|e| self.wrap_expr(e)), comma());
|
||||
let tail = tail.map(|e| self.expr(e));
|
||||
let tail = tail.map(|e| self.expr(e, false));
|
||||
list(elements_document, elements.len(), tail)
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1745,7 @@ impl<'comments> Formatter<'comments> {
|
|||
let right = self.clause_guard(right);
|
||||
self.operator_side(left, name_precedence, left_precedence)
|
||||
.append(name)
|
||||
.append(self.operator_side(right, name_precedence, right_precedence - 1))
|
||||
.append(self.operator_side(right, name_precedence, right_precedence.saturating_sub(1)))
|
||||
}
|
||||
|
||||
fn clause_guard<'a>(&mut self, clause_guard: &'a UntypedClauseGuard) -> Document<'a> {
|
||||
|
@ -1771,7 +1796,7 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
fn wrap_unary_op<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
|
||||
match expr {
|
||||
UntypedExpr::BinOp { .. } => "(".to_doc().append(self.expr(expr)).append(")"),
|
||||
UntypedExpr::BinOp { .. } => "(".to_doc().append(self.expr(expr, false)).append(")"),
|
||||
_ => self.wrap_expr(expr),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4049,6 +4049,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
Term::equals_string()
|
||||
} else if tipo.is_bytearray() {
|
||||
Term::equals_bytestring()
|
||||
} else if tipo.is_bls381_12_g1() {
|
||||
Term::bls12_381_g1_equal()
|
||||
} else if tipo.is_bls381_12_g2() {
|
||||
Term::bls12_381_g2_equal()
|
||||
} else if tipo.is_ml_result() {
|
||||
panic!("ML Result equality is not supported")
|
||||
} else {
|
||||
Term::equals_data()
|
||||
};
|
||||
|
|
|
@ -579,6 +579,12 @@ pub fn get_variant_name(t: &Rc<Type>) -> String {
|
|||
"_bool".to_string()
|
||||
} else if t.is_bytearray() {
|
||||
"_bytearray".to_string()
|
||||
} else if t.is_bls381_12_g1() {
|
||||
"_bls381_12_g1".to_string()
|
||||
} else if t.is_bls381_12_g2() {
|
||||
"_bls381_12_g2".to_string()
|
||||
} else if t.is_ml_result() {
|
||||
"_ml_result".to_string()
|
||||
} else if t.is_map() {
|
||||
let mut full_type = vec!["_map".to_string()];
|
||||
let pair_type = &t.get_inner_types()[0];
|
||||
|
@ -1305,7 +1311,7 @@ pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcCo
|
|||
UplcConstant::Bls12_381G2Element(b) => UplcConstant::Data(PlutusData::BoundedBytes(
|
||||
b.deref().clone().compress().into(),
|
||||
)),
|
||||
UplcConstant::Bls12_381MlResult(_) => unreachable!("Bls12_381MlResult not supported"),
|
||||
UplcConstant::Bls12_381MlResult(_) => panic!("Bls12_381MlResult not supported"),
|
||||
};
|
||||
new_constants.push(constant);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,25 @@ fn validator_illegal_return_type() {
|
|||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_useless_pub() {
|
||||
let source_code = r#"
|
||||
type Datum {
|
||||
thing: Int
|
||||
}
|
||||
|
||||
validator {
|
||||
pub fn foo(_d: Datum, _r, _c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let (warnings, _) = check_validator(parse(source_code)).unwrap();
|
||||
|
||||
assert!(matches!(warnings[0], Warning::PubInValidatorModule { .. }))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_illegal_arity() {
|
||||
let source_code = r#"
|
||||
|
|
|
@ -62,6 +62,77 @@ fn format_if() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_logic_op_with_code_block() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
True || {
|
||||
let bar = 1
|
||||
bar == bar
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_grouped_expression() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
y == { x |> f }
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_grouped_expression_2() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
( y == x ) |> f
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_grouped_expression_3() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
{ x |> f } == y
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_grouped_expression_4() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
x |> { f == y }
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_preserve_newline_after_bool_expect() {
|
||||
assert_format!(
|
||||
r#"
|
||||
fn foo() {
|
||||
expect 1 == 1
|
||||
|
||||
False
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_validator() {
|
||||
assert_format!(
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n y == { x |> f }\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
y == ( x |> f )
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n ( y == x ) |> f\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
( y == x ) |> f
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n { x |> f } == y\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
( x |> f ) == y
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n x |> { f == y }\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
x |> f == y
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n True || {\n let bar = 1\n bar == bar\n }\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
True || {
|
||||
let bar = 1
|
||||
bar == bar
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nfn foo() {\n expect 1 == 1\n\n False\n}\n"
|
||||
---
|
||||
fn foo() {
|
||||
expect 1 == 1
|
||||
|
||||
False
|
||||
}
|
||||
|
|
@ -1131,15 +1131,15 @@ fn suggest_constructor_pattern(
|
|||
}
|
||||
|
||||
fn suggest_unify(
|
||||
expected: &Rc<Type>,
|
||||
given: &Rc<Type>,
|
||||
expected: &Type,
|
||||
given: &Type,
|
||||
situation: &Option<UnifyErrorSituation>,
|
||||
rigid_type_names: &HashMap<u64, String>,
|
||||
) -> String {
|
||||
let expected_str = expected.to_pretty_with_names(rigid_type_names.clone(), 0);
|
||||
let given_str = given.to_pretty_with_names(rigid_type_names.clone(), 0);
|
||||
|
||||
let (expected, given) = match (expected.as_ref(), given.as_ref()) {
|
||||
let (expected, given) = match (expected, given) {
|
||||
(
|
||||
Type::App {
|
||||
module: expected_module,
|
||||
|
@ -1630,7 +1630,7 @@ pub enum UnknownRecordFieldSituation {
|
|||
|
||||
fn format_suggestion(sample: &UntypedExpr) -> String {
|
||||
Formatter::new()
|
||||
.expr(sample)
|
||||
.expr(sample, false)
|
||||
.to_pretty_string(70)
|
||||
.lines()
|
||||
.enumerate()
|
||||
|
|
|
@ -426,7 +426,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
tipo: string(),
|
||||
value: format!(
|
||||
"{} ? False",
|
||||
format::Formatter::new().expr(&value).to_pretty_string(999)
|
||||
format::Formatter::new()
|
||||
.expr(&value, false)
|
||||
.to_pretty_string(999)
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
@ -150,9 +150,9 @@ impl FieldMap {
|
|||
|
||||
self.fields
|
||||
.keys()
|
||||
.cloned()
|
||||
.filter(|f| !given.contains(f))
|
||||
.sorted()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ indexmap = "1.9.2"
|
|||
itertools = "0.10.5"
|
||||
miette = { version = "5.9.0", features = ["fancy"] }
|
||||
minicbor = "0.19.1"
|
||||
notify = "6.1.1"
|
||||
owo-colors = { version = "3.5.0", features = ["supports-colors"] }
|
||||
pallas = "0.18.0"
|
||||
pallas-traverse = "0.18.0"
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use crate::{
|
||||
blueprint::error as blueprint, deps::manifest::Package, package_name::PackageName, pretty,
|
||||
script::EvalHint,
|
||||
};
|
||||
use crate::{blueprint::error as blueprint, deps::manifest::Package, package_name::PackageName};
|
||||
use aiken_lang::{
|
||||
ast::{self, BinOp, Span},
|
||||
ast::{self, Span},
|
||||
error::ExtraData,
|
||||
parser::error::ParseError,
|
||||
tipo,
|
||||
|
@ -18,7 +15,6 @@ use std::{
|
|||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use uplc::machine::cost_model::ExBudget;
|
||||
use zip::result::ZipError;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -97,7 +93,7 @@ pub enum Error {
|
|||
path: PathBuf,
|
||||
verbose: bool,
|
||||
src: String,
|
||||
evaluation_hint: Option<EvalHint>,
|
||||
evaluation_hint: Option<String>,
|
||||
},
|
||||
|
||||
#[error(
|
||||
|
@ -266,31 +262,45 @@ impl Diagnostic for Error {
|
|||
}
|
||||
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
fn boxed<'a>(s: Box<dyn Display + 'a>) -> Box<dyn Display + 'a> {
|
||||
Box::new(format!(
|
||||
" {} {}",
|
||||
"Error"
|
||||
.if_supports_color(Stdout, |s| s.red())
|
||||
.if_supports_color(Stdout, |s| s.bold()),
|
||||
format!("{s}").if_supports_color(Stdout, |s| s.red())
|
||||
))
|
||||
}
|
||||
|
||||
match self {
|
||||
Error::DuplicateModule { .. } => Some(Box::new("aiken::module::duplicate")),
|
||||
Error::DuplicateModule { .. } => Some(boxed(Box::new("aiken::module::duplicate"))),
|
||||
Error::FileIo { .. } => None,
|
||||
Error::Blueprint(e) => e.code(),
|
||||
Error::ImportCycle { .. } => Some(Box::new("aiken::module::cyclical")),
|
||||
Error::Parse { .. } => Some(Box::new("aiken::parser")),
|
||||
Error::Type { error, .. } => Some(Box::new(format!(
|
||||
Error::Blueprint(e) => e.code().map(boxed),
|
||||
Error::ImportCycle { .. } => Some(boxed(Box::new("aiken::module::cyclical"))),
|
||||
Error::Parse { .. } => Some(boxed(Box::new("aiken::parser"))),
|
||||
Error::Type { error, .. } => Some(boxed(Box::new(format!(
|
||||
"aiken::check{}",
|
||||
error.code().map(|s| format!("::{s}")).unwrap_or_default()
|
||||
))),
|
||||
)))),
|
||||
Error::StandardIo(_) => None,
|
||||
Error::MissingManifest { .. } => None,
|
||||
Error::TomlLoading { .. } => Some(Box::new("aiken::loading::toml")),
|
||||
Error::TomlLoading { .. } => Some(boxed(Box::new("aiken::loading::toml"))),
|
||||
Error::Format { .. } => None,
|
||||
Error::TestFailure { path, .. } => Some(Box::new(path.to_str().unwrap_or(""))),
|
||||
Error::TestFailure { path, .. } => Some(boxed(Box::new(path.to_str().unwrap_or("")))),
|
||||
Error::Http(_) => Some(Box::new("aiken::packages::download")),
|
||||
Error::ZipExtract(_) => None,
|
||||
Error::JoinError(_) => None,
|
||||
Error::UnknownPackageVersion { .. } => Some(Box::new("aiken::packages::resolve")),
|
||||
Error::UnableToResolvePackage { .. } => Some(Box::new("aiken::package::download")),
|
||||
Error::UnknownPackageVersion { .. } => {
|
||||
Some(boxed(Box::new("aiken::packages::resolve")))
|
||||
}
|
||||
Error::UnableToResolvePackage { .. } => {
|
||||
Some(boxed(Box::new("aiken::package::download")))
|
||||
}
|
||||
Error::Json { .. } => None,
|
||||
Error::MalformedStakeAddress { .. } => None,
|
||||
Error::NoValidatorNotFound { .. } => None,
|
||||
Error::MoreThanOneValidatorFound { .. } => None,
|
||||
Error::Module(e) => e.code(),
|
||||
Error::Module(e) => e.code().map(boxed),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,33 +323,9 @@ impl Diagnostic for Error {
|
|||
Error::MissingManifest { .. } => Some(Box::new("Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.")),
|
||||
Error::TomlLoading { .. } => None,
|
||||
Error::Format { .. } => None,
|
||||
Error::TestFailure { evaluation_hint, .. } =>{
|
||||
match evaluation_hint {
|
||||
None => None,
|
||||
Some(hint) => {
|
||||
let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, };
|
||||
let left = pretty::boxed("left", &match hint.left.clone().eval(budget).result() {
|
||||
Ok(term) => format!("{term}"),
|
||||
Err(err) => format!("{err}"),
|
||||
});
|
||||
let right = pretty::boxed("right", &match hint.right.clone().eval(budget).result() {
|
||||
Ok(term) => format!("{term}"),
|
||||
Err(err) => format!("{err}"),
|
||||
});
|
||||
let msg = match hint.bin_op {
|
||||
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),
|
||||
BinOp::Or => Some(format!("{left}\n\nor\n\n{right}\n\nshould be true.")),
|
||||
BinOp::Eq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
|
||||
BinOp::NotEq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
|
||||
BinOp::LtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
|
||||
BinOp::LtEqInt => Some(format!("{left}\n\nshould be lower than or equal to\n\n{right}")),
|
||||
BinOp::GtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
|
||||
BinOp::GtInt => Some(format!("{left}\n\nshould be greater than or equal to\n\n{right}")),
|
||||
_ => None
|
||||
}?;
|
||||
Some(Box::new(msg))
|
||||
}
|
||||
}
|
||||
Error::TestFailure { evaluation_hint, .. } => match evaluation_hint {
|
||||
None => None,
|
||||
Some(hint) => Some(Box::new(hint.to_string()))
|
||||
},
|
||||
Error::Http(_) => None,
|
||||
Error::ZipExtract(_) => None,
|
||||
|
@ -560,14 +546,24 @@ impl Diagnostic for Warning {
|
|||
}
|
||||
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
fn boxed<'a>(s: Box<dyn Display + 'a>) -> Box<dyn Display + 'a> {
|
||||
Box::new(format!(
|
||||
" {} {}",
|
||||
"Warning"
|
||||
.if_supports_color(Stdout, |s| s.yellow())
|
||||
.if_supports_color(Stdout, |s| s.bold()),
|
||||
format!("{s}").if_supports_color(Stdout, |s| s.yellow())
|
||||
))
|
||||
}
|
||||
|
||||
match self {
|
||||
Warning::Type { warning, .. } => Some(Box::new(format!(
|
||||
Warning::Type { warning, .. } => Some(boxed(Box::new(format!(
|
||||
"aiken::check{}",
|
||||
warning.code().map(|s| format!("::{s}")).unwrap_or_default()
|
||||
))),
|
||||
Warning::NoValidators => Some(Box::new("aiken::check")),
|
||||
)))),
|
||||
Warning::NoValidators => Some(boxed(Box::new("aiken::check"))),
|
||||
Warning::DependencyAlreadyExists { .. } => {
|
||||
Some(Box::new("aiken::packages::already_exists"))
|
||||
Some(boxed(Box::new("aiken::packages::already_exists")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod script;
|
|||
pub mod telemetry;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod watch;
|
||||
|
||||
use crate::blueprint::{
|
||||
definitions::Definitions,
|
||||
|
@ -328,7 +329,11 @@ where
|
|||
Some(Error::TestFailure {
|
||||
name: e.script.name.clone(),
|
||||
path: e.script.input_path.clone(),
|
||||
evaluation_hint: e.script.evaluation_hint.clone(),
|
||||
evaluation_hint: e
|
||||
.script
|
||||
.evaluation_hint
|
||||
.as_ref()
|
||||
.map(|hint| hint.to_string()),
|
||||
src: e.script.program.to_pretty(),
|
||||
verbose,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{ExBudget, Term};
|
||||
use crate::{pretty, ExBudget, Term};
|
||||
use aiken_lang::ast::BinOp;
|
||||
use std::path::PathBuf;
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
path::PathBuf,
|
||||
};
|
||||
use uplc::ast::{NamedDeBruijn, Program};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -42,6 +45,48 @@ pub struct EvalHint {
|
|||
pub right: Program<NamedDeBruijn>,
|
||||
}
|
||||
|
||||
impl Display for EvalHint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let unlimited_budget = ExBudget {
|
||||
mem: i64::MAX,
|
||||
cpu: i64::MAX,
|
||||
};
|
||||
|
||||
let left = pretty::boxed(
|
||||
"left",
|
||||
&match self.left.clone().eval(unlimited_budget).result() {
|
||||
Ok(term) => format!("{term}"),
|
||||
Err(err) => format!("{err}"),
|
||||
},
|
||||
);
|
||||
let right = pretty::boxed(
|
||||
"right",
|
||||
&match self.right.clone().eval(unlimited_budget).result() {
|
||||
Ok(term) => format!("{term}"),
|
||||
Err(err) => format!("{err}"),
|
||||
},
|
||||
);
|
||||
let msg = match self.bin_op {
|
||||
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),
|
||||
BinOp::Or => Some(format!("{left}\n\nor\n\n{right}\n\nshould be true.")),
|
||||
BinOp::Eq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
|
||||
BinOp::NotEq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
|
||||
BinOp::LtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
|
||||
BinOp::LtEqInt => Some(format!(
|
||||
"{left}\n\nshould be lower than or equal to\n\n{right}"
|
||||
)),
|
||||
BinOp::GtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
|
||||
BinOp::GtInt => Some(format!(
|
||||
"{left}\n\nshould be greater than or equal to\n\n{right}"
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(fmt::Error)?;
|
||||
|
||||
f.write_str(&msg)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EvalInfo {
|
||||
pub success: bool,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use crate::pretty;
|
||||
use crate::script::EvalInfo;
|
||||
use std::{fmt::Display, path::PathBuf};
|
||||
use owo_colors::{
|
||||
OwoColorize,
|
||||
Stream::{self, Stderr},
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt::Display, path::PathBuf};
|
||||
use uplc::machine::cost_model::ExBudget;
|
||||
|
||||
pub trait EventListener {
|
||||
fn handle_event(&self, _event: Event) {}
|
||||
|
@ -64,3 +70,339 @@ impl Display for DownloadSource {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct Terminal;
|
||||
|
||||
impl EventListener for Terminal {
|
||||
fn handle_event(&self, event: Event) {
|
||||
match event {
|
||||
Event::StartingCompilation {
|
||||
name,
|
||||
version,
|
||||
root,
|
||||
} => {
|
||||
eprintln!(
|
||||
"{} {} {} ({})",
|
||||
" Compiling"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold()),
|
||||
version,
|
||||
root.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
Event::BuildingDocumentation {
|
||||
name,
|
||||
version,
|
||||
root,
|
||||
} => {
|
||||
eprintln!(
|
||||
"{} {} {} ({})",
|
||||
" Generating documentation"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold()),
|
||||
version,
|
||||
root.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
Event::WaitingForBuildDirLock => {
|
||||
eprintln!(
|
||||
"{}",
|
||||
"Waiting for build directory lock ..."
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
);
|
||||
}
|
||||
Event::DumpingUPLC { path } => {
|
||||
eprintln!(
|
||||
"{} {} ({})",
|
||||
" Exporting"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"UPLC".if_supports_color(Stderr, |s| s.bold()),
|
||||
path.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
Event::GeneratingBlueprint { path } => {
|
||||
eprintln!(
|
||||
"{} {} ({})",
|
||||
" Generating"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"project's blueprint".if_supports_color(Stderr, |s| s.bold()),
|
||||
path.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
Event::GeneratingDocFiles { output_path } => {
|
||||
eprintln!(
|
||||
"{} in {}",
|
||||
" Generating documentation files"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
output_path
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
Event::GeneratingUPLCFor { name, path } => {
|
||||
eprintln!(
|
||||
"{} {}.{{{}}}",
|
||||
" Generating UPLC for"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
path.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.blue()),
|
||||
name.if_supports_color(Stderr, |s| s.bright_blue()),
|
||||
);
|
||||
}
|
||||
Event::EvaluatingFunction { results } => {
|
||||
eprintln!(
|
||||
"{}\n",
|
||||
" Evaluating function ..."
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
);
|
||||
|
||||
let (max_mem, max_cpu) = find_max_execution_units(&results);
|
||||
|
||||
for eval_info in &results {
|
||||
println!(" {}", fmt_eval(eval_info, max_mem, max_cpu, Stderr))
|
||||
}
|
||||
}
|
||||
Event::RunningTests => {
|
||||
eprintln!(
|
||||
"{} {}\n",
|
||||
" Testing"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"...".if_supports_color(Stderr, |s| s.bold())
|
||||
);
|
||||
}
|
||||
Event::FinishedTests { tests } => {
|
||||
let (max_mem, max_cpu) = find_max_execution_units(&tests);
|
||||
|
||||
for (module, infos) in &group_by_module(&tests) {
|
||||
let title = module
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.blue())
|
||||
.to_string();
|
||||
|
||||
let tests = infos
|
||||
.iter()
|
||||
.map(|eval_info| fmt_test(eval_info, max_mem, max_cpu, true))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
let summary = fmt_test_summary(infos, true);
|
||||
|
||||
eprintln!(
|
||||
"{}\n",
|
||||
pretty::indent(
|
||||
&pretty::open_box(&title, &tests, &summary, |border| border
|
||||
.if_supports_color(Stderr, |s| s.bright_black())
|
||||
.to_string()),
|
||||
4
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::ResolvingPackages { name } => {
|
||||
eprintln!(
|
||||
"{} {}",
|
||||
" Resolving"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold())
|
||||
)
|
||||
}
|
||||
Event::PackageResolveFallback { name } => {
|
||||
eprintln!(
|
||||
"{} {}\n ↳ You're seeing this message because the package version is unpinned and the network is not accessible.",
|
||||
" Using"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.yellow()),
|
||||
format!("uncertain local version for {name}")
|
||||
.if_supports_color(Stderr, |s| s.yellow())
|
||||
)
|
||||
}
|
||||
Event::PackagesDownloaded {
|
||||
start,
|
||||
count,
|
||||
source,
|
||||
} => {
|
||||
let elapsed = format!("{:.2}s", start.elapsed().as_millis() as f32 / 1000.);
|
||||
|
||||
let msg = match count {
|
||||
1 => format!("1 package in {elapsed}"),
|
||||
_ => format!("{count} packages in {elapsed}"),
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"{} {} from {source}",
|
||||
match source {
|
||||
DownloadSource::Network => " Downloaded",
|
||||
DownloadSource::Cache => " Fetched",
|
||||
}
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
msg.if_supports_color(Stderr, |s| s.bold())
|
||||
)
|
||||
}
|
||||
Event::ResolvingVersions => {
|
||||
eprintln!(
|
||||
"{}",
|
||||
" Resolving dependencies"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_test(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, styled: bool) -> String {
|
||||
let EvalInfo {
|
||||
success,
|
||||
script,
|
||||
spent_budget,
|
||||
logs,
|
||||
..
|
||||
} = eval_info;
|
||||
|
||||
let ExBudget { mem, cpu } = spent_budget;
|
||||
let mem_pad = pretty::pad_left(mem.to_string(), max_mem, " ");
|
||||
let cpu_pad = pretty::pad_left(cpu.to_string(), max_cpu, " ");
|
||||
|
||||
let test = format!(
|
||||
"{status} [mem: {mem_unit}, cpu: {cpu_unit}] {module}",
|
||||
status = if *success {
|
||||
pretty::style_if(styled, "PASS".to_string(), |s| {
|
||||
s.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.green())
|
||||
.to_string()
|
||||
})
|
||||
} else {
|
||||
pretty::style_if(styled, "FAIL".to_string(), |s| {
|
||||
s.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.red())
|
||||
.to_string()
|
||||
})
|
||||
},
|
||||
mem_unit = pretty::style_if(styled, mem_pad, |s| s
|
||||
.if_supports_color(Stderr, |s| s.cyan())
|
||||
.to_string()),
|
||||
cpu_unit = pretty::style_if(styled, cpu_pad, |s| s
|
||||
.if_supports_color(Stderr, |s| s.cyan())
|
||||
.to_string()),
|
||||
module = pretty::style_if(styled, script.name.clone(), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
.to_string()),
|
||||
);
|
||||
|
||||
let logs = if logs.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
logs.iter()
|
||||
.map(|line| {
|
||||
format!(
|
||||
"{arrow} {styled_line}",
|
||||
arrow = "↳".if_supports_color(Stderr, |s| s.bright_yellow()),
|
||||
styled_line = line.if_supports_color(Stderr, |s| s.bright_black())
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
if logs.is_empty() {
|
||||
test
|
||||
} else {
|
||||
[test, logs].join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_test_summary(tests: &Vec<&EvalInfo>, styled: bool) -> String {
|
||||
let (n_passed, n_failed) = tests
|
||||
.iter()
|
||||
.fold((0, 0), |(n_passed, n_failed), test_info| {
|
||||
if test_info.success {
|
||||
(n_passed + 1, n_failed)
|
||||
} else {
|
||||
(n_passed, n_failed + 1)
|
||||
}
|
||||
});
|
||||
format!(
|
||||
"{} | {} | {}",
|
||||
pretty::style_if(styled, format!("{} tests", tests.len()), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
pretty::style_if(styled, format!("{n_passed} passed"), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_green())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
pretty::style_if(styled, format!("{n_failed} failed"), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_red())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_eval(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, stream: Stream) -> String {
|
||||
let EvalInfo {
|
||||
output,
|
||||
script,
|
||||
spent_budget,
|
||||
..
|
||||
} = eval_info;
|
||||
|
||||
let ExBudget { mem, cpu } = spent_budget;
|
||||
|
||||
format!(
|
||||
" {}::{} [mem: {}, cpu: {}]\n │\n ╰─▶ {}",
|
||||
script.module.if_supports_color(stream, |s| s.blue()),
|
||||
script.name.if_supports_color(stream, |s| s.bright_blue()),
|
||||
pretty::pad_left(mem.to_string(), max_mem, " "),
|
||||
pretty::pad_left(cpu.to_string(), max_cpu, " "),
|
||||
output
|
||||
.as_ref()
|
||||
.map(|x| format!("{x}"))
|
||||
.unwrap_or_else(|| "Error.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn group_by_module(infos: &Vec<EvalInfo>) -> BTreeMap<String, Vec<&EvalInfo>> {
|
||||
let mut modules = BTreeMap::new();
|
||||
for eval_info in infos {
|
||||
let xs: &mut Vec<&EvalInfo> = modules.entry(eval_info.script.module.clone()).or_default();
|
||||
xs.push(eval_info);
|
||||
}
|
||||
modules
|
||||
}
|
||||
|
||||
fn find_max_execution_units(xs: &[EvalInfo]) -> (usize, usize) {
|
||||
let (max_mem, max_cpu) = xs.iter().fold(
|
||||
(0, 0),
|
||||
|(max_mem, max_cpu), EvalInfo { spent_budget, .. }| {
|
||||
if spent_budget.mem >= max_mem && spent_budget.cpu >= max_cpu {
|
||||
(spent_budget.mem, spent_budget.cpu)
|
||||
} else if spent_budget.mem > max_mem {
|
||||
(spent_budget.mem, max_cpu)
|
||||
} else if spent_budget.cpu > max_cpu {
|
||||
(max_mem, spent_budget.cpu)
|
||||
} else {
|
||||
(max_mem, max_cpu)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
(max_mem.to_string().len(), max_cpu.to_string().len())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
use crate::{telemetry::Terminal, Project};
|
||||
use miette::{Diagnostic, IntoDiagnostic};
|
||||
use notify::{Event, RecursiveMode, Watcher};
|
||||
use owo_colors::{OwoColorize, Stream::Stderr};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
env,
|
||||
ffi::OsStr,
|
||||
fmt::{self, Display},
|
||||
path::Path,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
#[derive(Debug, Diagnostic, thiserror::Error)]
|
||||
enum ExitFailure {
|
||||
#[error("")]
|
||||
ExitFailure,
|
||||
}
|
||||
|
||||
impl ExitFailure {
|
||||
fn into_report() -> miette::Report {
|
||||
ExitFailure::ExitFailure.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Summary {
|
||||
warning_count: usize,
|
||||
error_count: usize,
|
||||
}
|
||||
|
||||
impl Display for Summary {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&format!(
|
||||
" {} {} {}, {} {}",
|
||||
"Summary"
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
.if_supports_color(Stderr, |s| s.bold()),
|
||||
self.error_count,
|
||||
if self.error_count == 1 {
|
||||
"error"
|
||||
} else {
|
||||
"errors"
|
||||
}
|
||||
.if_supports_color(Stderr, |s| s.red())
|
||||
.if_supports_color(Stderr, |s| s.bold()),
|
||||
self.warning_count,
|
||||
if self.warning_count == 1 {
|
||||
"warning"
|
||||
} else {
|
||||
"warnings"
|
||||
}
|
||||
.if_supports_color(Stderr, |s| s.yellow())
|
||||
.if_supports_color(Stderr, |s| s.bold()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A default filter for file events that catches the most relevant "source" changes
|
||||
pub fn default_filter(evt: &Event) -> bool {
|
||||
// Only watch for changes to .ak and aiken.toml files, and ignore the build directory
|
||||
let source_file = evt
|
||||
.paths
|
||||
.iter()
|
||||
.any(|p| p.extension() == Some(OsStr::new("ak")) || p.ends_with("aiken.toml"));
|
||||
let build_dir = evt
|
||||
.paths
|
||||
.iter()
|
||||
.all(|p| p.ancestors().any(|a| a.ends_with("build")));
|
||||
match evt.kind {
|
||||
notify::EventKind::Any => true,
|
||||
notify::EventKind::Create(_)
|
||||
| notify::EventKind::Modify(_)
|
||||
| notify::EventKind::Remove(_) => source_file && !build_dir,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_project<A>(directory: Option<&Path>, deny: bool, mut action: A) -> miette::Result<()>
|
||||
where
|
||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<crate::error::Error>>,
|
||||
{
|
||||
let project_path = if let Some(d) = directory {
|
||||
d.to_path_buf()
|
||||
} else {
|
||||
env::current_dir().into_diagnostic()?
|
||||
};
|
||||
|
||||
let mut project = match Project::new(project_path, Terminal) {
|
||||
Ok(p) => Ok(p),
|
||||
Err(e) => {
|
||||
e.report();
|
||||
Err(ExitFailure::into_report())
|
||||
}
|
||||
}?;
|
||||
|
||||
let build_result = action(&mut project);
|
||||
|
||||
let warnings = project.warnings();
|
||||
|
||||
let warning_count = warnings.len();
|
||||
|
||||
for warning in &warnings {
|
||||
warning.report()
|
||||
}
|
||||
|
||||
if let Err(errs) = build_result {
|
||||
for err in &errs {
|
||||
err.report()
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"{}",
|
||||
Summary {
|
||||
warning_count,
|
||||
error_count: errs.len(),
|
||||
}
|
||||
);
|
||||
|
||||
return Err(ExitFailure::into_report());
|
||||
} else {
|
||||
eprintln!(
|
||||
"{}",
|
||||
Summary {
|
||||
error_count: 0,
|
||||
warning_count
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if warning_count > 0 && deny {
|
||||
Err(ExitFailure::into_report())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a function each time a file in the project changes
|
||||
///
|
||||
/// ```text
|
||||
/// // Note: doctest disabled, because aiken_project doesn't have an implementation of EventListener I can use
|
||||
/// use aiken_project::watch::{watch_project, default_filter};
|
||||
/// use aiken_project::{Project};
|
||||
/// watch_project(None, Terminal, default_filter, 500, |project| {
|
||||
/// println!("Project changed!");
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn watch_project<F, A>(
|
||||
directory: Option<&Path>,
|
||||
filter: F,
|
||||
debounce: u32,
|
||||
mut action: A,
|
||||
) -> miette::Result<()>
|
||||
where
|
||||
F: Fn(&Event) -> bool,
|
||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<crate::error::Error>>,
|
||||
{
|
||||
let project_path = directory
|
||||
.map(|p| p.to_path_buf())
|
||||
.unwrap_or(env::current_dir().into_diagnostic()?);
|
||||
|
||||
// Set up a queue for events, primarily so we can debounce on related events
|
||||
let queue = Arc::new(Mutex::new(VecDeque::new()));
|
||||
|
||||
// Run the action once, to start
|
||||
queue
|
||||
.lock()
|
||||
.expect("lock queue")
|
||||
.push_back(Event::default());
|
||||
|
||||
// Spawn a file-watcher that will put each change event on the queue
|
||||
let queue_write = queue.clone();
|
||||
let mut watcher = notify::recommended_watcher(move |res: notify::Result<Event>| {
|
||||
match res {
|
||||
Ok(event) => queue_write
|
||||
.lock()
|
||||
.expect("lock queue")
|
||||
.push_back(event.clone()),
|
||||
Err(e) => {
|
||||
// TODO: miette diagnostic?
|
||||
println!(
|
||||
"Encountered an error while monitoring for file changes: {:?}",
|
||||
e
|
||||
)
|
||||
}
|
||||
};
|
||||
})
|
||||
.into_diagnostic()?;
|
||||
|
||||
// Start watching for any changes in the project directory
|
||||
let _ = watcher.watch(project_path.as_path(), RecursiveMode::Recursive);
|
||||
|
||||
// And then start reading from the queue
|
||||
let queue_read = queue.clone();
|
||||
loop {
|
||||
// We sleep for the debounce interval, because notify will dump 12 related events into the queue all at once
|
||||
std::thread::sleep(std::time::Duration::from_millis(debounce.into()));
|
||||
|
||||
// Grab the lock, and pop all events except the last one off the queue
|
||||
let mut queue = queue_read.lock().expect("lock queue");
|
||||
let mut latest = None;
|
||||
// debounce the events, and ignore build/lock changes, because they come in in large batches
|
||||
while let Some(evt) = queue.pop_back() {
|
||||
// check if this event is meaningful to the caller
|
||||
if !filter(&evt) {
|
||||
continue;
|
||||
}
|
||||
latest = Some(evt);
|
||||
}
|
||||
// release the lock here, in case other events come in
|
||||
drop(queue);
|
||||
|
||||
// If we have an event that survived the filter, then we can construct the project and invoke the action
|
||||
if latest.is_some() {
|
||||
print!("{esc}c", esc = 27 as char);
|
||||
println!(
|
||||
"{} ...",
|
||||
" Watching"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
);
|
||||
with_project(directory, false, &mut action).unwrap_or(())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use crate::with_project;
|
||||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Compute a validator's address.
|
||||
|
@ -34,7 +34,7 @@ pub fn exec(
|
|||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory, false, |p| {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::NoTraces)?;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::with_project;
|
||||
use aiken_project::{
|
||||
blueprint::{
|
||||
self,
|
||||
|
@ -7,6 +6,7 @@ use aiken_project::{
|
|||
},
|
||||
error::Error,
|
||||
pretty::multiline,
|
||||
watch::with_project,
|
||||
};
|
||||
use inquire;
|
||||
use num_bigint::BigInt;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::with_project;
|
||||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Compute a validator's hash
|
||||
|
@ -29,7 +29,7 @@ pub fn exec(
|
|||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory, false, |p| {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::NoTraces)?;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::with_project;
|
||||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Compute a minting scripts Policy ID
|
||||
|
@ -29,7 +29,7 @@ pub fn exec(
|
|||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory, false, |p| {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::NoTraces)?;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use aiken_project::watch::{self, watch_project, with_project};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -10,6 +11,10 @@ pub struct Args {
|
|||
#[clap(short = 'D', long)]
|
||||
deny: bool,
|
||||
|
||||
/// When enabled, re-run the command on file changes instead of exiting
|
||||
#[clap(short, long)]
|
||||
watch: bool,
|
||||
|
||||
/// Also dump textual uplc
|
||||
#[clap(short, long)]
|
||||
uplc: bool,
|
||||
|
@ -23,9 +28,18 @@ pub fn exec(
|
|||
Args {
|
||||
directory,
|
||||
deny,
|
||||
watch,
|
||||
uplc,
|
||||
keep_traces,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
crate::with_project(directory, deny, |p| p.build(uplc, keep_traces.into()))
|
||||
if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
p.build(uplc, keep_traces.into())
|
||||
})
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| {
|
||||
p.build(uplc, keep_traces.into())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use aiken_project::watch::{self, watch_project, with_project};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -18,6 +19,10 @@ pub struct Args {
|
|||
#[clap(long)]
|
||||
debug: bool,
|
||||
|
||||
/// When enabled, re-run the command on file changes instead of exiting
|
||||
#[clap(long)]
|
||||
watch: bool,
|
||||
|
||||
/// Only run tests if they match any of these strings.
|
||||
/// You can match a module with `-m aiken/list` or `-m list`.
|
||||
/// You can match a test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"`
|
||||
|
@ -43,15 +48,29 @@ pub fn exec(
|
|||
match_tests,
|
||||
exact_match,
|
||||
no_traces,
|
||||
watch,
|
||||
..
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
crate::with_project(directory, deny, |p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
(!no_traces).into(),
|
||||
)
|
||||
})
|
||||
if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
(!no_traces).into(),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
(!no_traces).into(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use aiken_project::watch::{self, watch_project, with_project};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -10,6 +11,10 @@ pub struct Args {
|
|||
#[clap(short = 'D', long)]
|
||||
deny: bool,
|
||||
|
||||
/// When enabled, re-run the command on file changes instead of exiting
|
||||
#[clap(short, long)]
|
||||
watch: bool,
|
||||
|
||||
/// Output directory for the documentation
|
||||
#[clap(short = 'o', long)]
|
||||
destination: Option<PathBuf>,
|
||||
|
@ -19,8 +24,15 @@ pub fn exec(
|
|||
Args {
|
||||
directory,
|
||||
deny,
|
||||
watch,
|
||||
destination,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
crate::with_project(directory, deny, |p| p.docs(destination.clone()))
|
||||
if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
p.docs(destination.clone())
|
||||
})
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| p.docs(destination.clone()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,431 +0,0 @@
|
|||
use aiken_project::{
|
||||
pretty,
|
||||
script::EvalInfo,
|
||||
telemetry::{self, DownloadSource},
|
||||
Project,
|
||||
};
|
||||
use miette::IntoDiagnostic;
|
||||
use owo_colors::{
|
||||
OwoColorize,
|
||||
Stream::{self, Stderr},
|
||||
};
|
||||
use std::{collections::BTreeMap, env, path::PathBuf, process};
|
||||
use uplc::machine::cost_model::ExBudget;
|
||||
|
||||
pub mod cmd;
|
||||
|
||||
pub fn with_project<A>(directory: Option<PathBuf>, deny: bool, mut action: A) -> miette::Result<()>
|
||||
where
|
||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<aiken_project::error::Error>>,
|
||||
{
|
||||
let project_path = if let Some(d) = directory {
|
||||
d
|
||||
} else {
|
||||
env::current_dir().into_diagnostic()?
|
||||
};
|
||||
|
||||
let mut project = match Project::new(project_path, Terminal) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
e.report();
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let build_result = action(&mut project);
|
||||
|
||||
let warnings = project.warnings();
|
||||
|
||||
let warning_count = warnings.len();
|
||||
|
||||
for warning in &warnings {
|
||||
warning.report()
|
||||
}
|
||||
|
||||
let plural = if warning_count == 1 { "" } else { "s" };
|
||||
|
||||
if let Err(errs) = build_result {
|
||||
for err in &errs {
|
||||
err.report()
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"\n{}",
|
||||
"Summary"
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
);
|
||||
|
||||
let warning_text = format!("{warning_count} warning{plural}");
|
||||
|
||||
let plural = if errs.len() == 1 { "" } else { "s" };
|
||||
|
||||
let error_text = format!("{} error{}", errs.len(), plural);
|
||||
|
||||
let full_summary = format!(
|
||||
" {}, {}",
|
||||
error_text.if_supports_color(Stderr, |s| s.red()),
|
||||
warning_text.if_supports_color(Stderr, |s| s.yellow())
|
||||
);
|
||||
|
||||
eprintln!("{full_summary}");
|
||||
|
||||
process::exit(1);
|
||||
} else {
|
||||
eprintln!(
|
||||
"\n{}",
|
||||
"Summary"
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
);
|
||||
|
||||
let warning_text = format!("{warning_count} warning{plural}");
|
||||
|
||||
eprintln!(
|
||||
" 0 errors, {}",
|
||||
warning_text.if_supports_color(Stderr, |s| s.yellow()),
|
||||
);
|
||||
}
|
||||
|
||||
if warning_count > 0 && deny {
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct Terminal;
|
||||
|
||||
impl telemetry::EventListener for Terminal {
|
||||
fn handle_event(&self, event: telemetry::Event) {
|
||||
match event {
|
||||
telemetry::Event::StartingCompilation {
|
||||
name,
|
||||
version,
|
||||
root,
|
||||
} => {
|
||||
eprintln!(
|
||||
"{} {} {} ({})",
|
||||
" Compiling"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold()),
|
||||
version,
|
||||
root.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
telemetry::Event::BuildingDocumentation {
|
||||
name,
|
||||
version,
|
||||
root,
|
||||
} => {
|
||||
eprintln!(
|
||||
"{} {} {} ({})",
|
||||
" Generating documentation"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold()),
|
||||
version,
|
||||
root.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
telemetry::Event::WaitingForBuildDirLock => {
|
||||
eprintln!(
|
||||
"{}",
|
||||
"Waiting for build directory lock ..."
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
);
|
||||
}
|
||||
telemetry::Event::DumpingUPLC { path } => {
|
||||
eprintln!(
|
||||
"{} {} ({})",
|
||||
" Exporting"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"UPLC".if_supports_color(Stderr, |s| s.bold()),
|
||||
path.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
telemetry::Event::GeneratingBlueprint { path } => {
|
||||
eprintln!(
|
||||
"{} {} ({})",
|
||||
" Generating"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"project's blueprint".if_supports_color(Stderr, |s| s.bold()),
|
||||
path.display()
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
telemetry::Event::GeneratingDocFiles { output_path } => {
|
||||
eprintln!(
|
||||
"{} in {}",
|
||||
" Generating documentation files"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
output_path
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
);
|
||||
}
|
||||
telemetry::Event::GeneratingUPLCFor { name, path } => {
|
||||
eprintln!(
|
||||
"{} {}.{{{}}}",
|
||||
" Generating UPLC for"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
path.to_str()
|
||||
.unwrap_or("")
|
||||
.if_supports_color(Stderr, |s| s.blue()),
|
||||
name.if_supports_color(Stderr, |s| s.bright_blue()),
|
||||
);
|
||||
}
|
||||
telemetry::Event::EvaluatingFunction { results } => {
|
||||
eprintln!(
|
||||
"{}\n",
|
||||
" Evaluating function ..."
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple())
|
||||
);
|
||||
|
||||
let (max_mem, max_cpu) = find_max_execution_units(&results);
|
||||
|
||||
for eval_info in &results {
|
||||
println!(" {}", fmt_eval(eval_info, max_mem, max_cpu, Stderr))
|
||||
}
|
||||
}
|
||||
telemetry::Event::RunningTests => {
|
||||
eprintln!(
|
||||
"{} {}\n",
|
||||
" Testing"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
"...".if_supports_color(Stderr, |s| s.bold())
|
||||
);
|
||||
}
|
||||
telemetry::Event::FinishedTests { tests } => {
|
||||
let (max_mem, max_cpu) = find_max_execution_units(&tests);
|
||||
|
||||
for (module, infos) in &group_by_module(&tests) {
|
||||
let title = module
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.blue())
|
||||
.to_string();
|
||||
|
||||
let tests = infos
|
||||
.iter()
|
||||
.map(|eval_info| fmt_test(eval_info, max_mem, max_cpu, true))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
let summary = fmt_test_summary(infos, true);
|
||||
|
||||
eprintln!(
|
||||
"{}\n",
|
||||
pretty::indent(
|
||||
&pretty::open_box(&title, &tests, &summary, |border| border
|
||||
.if_supports_color(Stderr, |s| s.bright_black())
|
||||
.to_string()),
|
||||
4
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
telemetry::Event::ResolvingPackages { name } => {
|
||||
eprintln!(
|
||||
"{} {}",
|
||||
" Resolving"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
name.if_supports_color(Stderr, |s| s.bold())
|
||||
)
|
||||
}
|
||||
telemetry::Event::PackageResolveFallback { name } => {
|
||||
eprintln!(
|
||||
"{} {}\n ↳ You're seeing this message because the package version is unpinned and the network is not accessible.",
|
||||
" Using"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.yellow()),
|
||||
format!("uncertain local version for {name}")
|
||||
.if_supports_color(Stderr, |s| s.yellow())
|
||||
)
|
||||
}
|
||||
telemetry::Event::PackagesDownloaded {
|
||||
start,
|
||||
count,
|
||||
source,
|
||||
} => {
|
||||
let elapsed = format!("{:.2}s", start.elapsed().as_millis() as f32 / 1000.);
|
||||
|
||||
let msg = match count {
|
||||
1 => format!("1 package in {elapsed}"),
|
||||
_ => format!("{count} packages in {elapsed}"),
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"{} {} from {source}",
|
||||
match source {
|
||||
DownloadSource::Network => " Downloaded",
|
||||
DownloadSource::Cache => " Fetched",
|
||||
}
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
msg.if_supports_color(Stderr, |s| s.bold())
|
||||
)
|
||||
}
|
||||
telemetry::Event::ResolvingVersions => {
|
||||
eprintln!(
|
||||
"{}",
|
||||
" Resolving dependencies"
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_test(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, styled: bool) -> String {
|
||||
let EvalInfo {
|
||||
success,
|
||||
script,
|
||||
spent_budget,
|
||||
logs,
|
||||
..
|
||||
} = eval_info;
|
||||
|
||||
let ExBudget { mem, cpu } = spent_budget;
|
||||
let mem_pad = pretty::pad_left(mem.to_string(), max_mem, " ");
|
||||
let cpu_pad = pretty::pad_left(cpu.to_string(), max_cpu, " ");
|
||||
|
||||
let test = format!(
|
||||
"{status} [mem: {mem_unit}, cpu: {cpu_unit}] {module}",
|
||||
status = if *success {
|
||||
pretty::style_if(styled, "PASS".to_string(), |s| {
|
||||
s.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.green())
|
||||
.to_string()
|
||||
})
|
||||
} else {
|
||||
pretty::style_if(styled, "FAIL".to_string(), |s| {
|
||||
s.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.red())
|
||||
.to_string()
|
||||
})
|
||||
},
|
||||
mem_unit = pretty::style_if(styled, mem_pad, |s| s
|
||||
.if_supports_color(Stderr, |s| s.cyan())
|
||||
.to_string()),
|
||||
cpu_unit = pretty::style_if(styled, cpu_pad, |s| s
|
||||
.if_supports_color(Stderr, |s| s.cyan())
|
||||
.to_string()),
|
||||
module = pretty::style_if(styled, script.name.clone(), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||
.to_string()),
|
||||
);
|
||||
|
||||
let logs = if logs.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
logs.iter()
|
||||
.map(|line| {
|
||||
format!(
|
||||
"{arrow} {styled_line}",
|
||||
arrow = "↳".if_supports_color(Stderr, |s| s.bright_yellow()),
|
||||
styled_line = line.if_supports_color(Stderr, |s| s.bright_black())
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
if logs.is_empty() {
|
||||
test
|
||||
} else {
|
||||
[test, logs].join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_test_summary(tests: &Vec<&EvalInfo>, styled: bool) -> String {
|
||||
let (n_passed, n_failed) = tests
|
||||
.iter()
|
||||
.fold((0, 0), |(n_passed, n_failed), test_info| {
|
||||
if test_info.success {
|
||||
(n_passed + 1, n_failed)
|
||||
} else {
|
||||
(n_passed, n_failed + 1)
|
||||
}
|
||||
});
|
||||
format!(
|
||||
"{} | {} | {}",
|
||||
pretty::style_if(styled, format!("{} tests", tests.len()), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
pretty::style_if(styled, format!("{n_passed} passed"), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_green())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
pretty::style_if(styled, format!("{n_failed} failed"), |s| s
|
||||
.if_supports_color(Stderr, |s| s.bright_red())
|
||||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_eval(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, stream: Stream) -> String {
|
||||
let EvalInfo {
|
||||
output,
|
||||
script,
|
||||
spent_budget,
|
||||
..
|
||||
} = eval_info;
|
||||
|
||||
let ExBudget { mem, cpu } = spent_budget;
|
||||
|
||||
format!(
|
||||
" {}::{} [mem: {}, cpu: {}]\n │\n ╰─▶ {}",
|
||||
script.module.if_supports_color(stream, |s| s.blue()),
|
||||
script.name.if_supports_color(stream, |s| s.bright_blue()),
|
||||
pretty::pad_left(mem.to_string(), max_mem, " "),
|
||||
pretty::pad_left(cpu.to_string(), max_cpu, " "),
|
||||
output
|
||||
.as_ref()
|
||||
.map(|x| format!("{x}"))
|
||||
.unwrap_or_else(|| "Error.".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn group_by_module(infos: &Vec<EvalInfo>) -> BTreeMap<String, Vec<&EvalInfo>> {
|
||||
let mut modules = BTreeMap::new();
|
||||
for eval_info in infos {
|
||||
let xs: &mut Vec<&EvalInfo> = modules.entry(eval_info.script.module.clone()).or_default();
|
||||
xs.push(eval_info);
|
||||
}
|
||||
modules
|
||||
}
|
||||
|
||||
fn find_max_execution_units(xs: &[EvalInfo]) -> (usize, usize) {
|
||||
let (max_mem, max_cpu) = xs.iter().fold(
|
||||
(0, 0),
|
||||
|(max_mem, max_cpu), EvalInfo { spent_budget, .. }| {
|
||||
if spent_budget.mem >= max_mem && spent_budget.cpu >= max_cpu {
|
||||
(spent_budget.mem, spent_budget.cpu)
|
||||
} else if spent_budget.mem > max_mem {
|
||||
(spent_budget.mem, max_cpu)
|
||||
} else if spent_budget.cpu > max_cpu {
|
||||
(max_mem, spent_budget.cpu)
|
||||
} else {
|
||||
(max_mem, max_cpu)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
(max_mem.to_string().len(), max_cpu.to_string().len())
|
||||
}
|
|
@ -1,17 +1,19 @@
|
|||
use aiken::cmd::{
|
||||
use aiken_project::{config, pretty};
|
||||
use cmd::{
|
||||
blueprint::{self, address},
|
||||
build, check, completion, docs, fmt, lsp, new,
|
||||
packages::{self, add},
|
||||
tx, uplc, Cmd,
|
||||
};
|
||||
use aiken_project::{config, pretty};
|
||||
|
||||
use owo_colors::OwoColorize;
|
||||
use std::process;
|
||||
|
||||
fn main() -> miette::Result<()> {
|
||||
mod cmd;
|
||||
|
||||
fn main() {
|
||||
panic_handler();
|
||||
|
||||
match Cmd::default() {
|
||||
let result = match Cmd::default() {
|
||||
Cmd::New(args) => new::exec(args),
|
||||
Cmd::Fmt(args) => fmt::exec(args),
|
||||
Cmd::Build(args) => build::exec(args),
|
||||
|
@ -25,6 +27,11 @@ fn main() -> miette::Result<()> {
|
|||
Cmd::Tx(sub_cmd) => tx::exec(sub_cmd),
|
||||
Cmd::Uplc(sub_cmd) => uplc::exec(sub_cmd),
|
||||
Cmd::Completion(sub_cmd) => completion::exec(sub_cmd),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(()) => (),
|
||||
Err(_) => process::exit(1),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -240,9 +240,12 @@ impl Machine {
|
|||
env,
|
||||
t.clone(),
|
||||
)),
|
||||
None => todo!(),
|
||||
None => Err(Error::MissingCaseBranch(
|
||||
branches,
|
||||
Value::Constr { tag, fields },
|
||||
)),
|
||||
},
|
||||
_ => todo!("return a proper evaluation error"),
|
||||
v => Err(Error::NonConstrScrutinized(v)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,12 +186,12 @@ impl Default for MachineCosts {
|
|||
},
|
||||
// Placeholder values
|
||||
constr: ExBudget {
|
||||
mem: 30000000000,
|
||||
cpu: 30000000000,
|
||||
mem: 100,
|
||||
cpu: 23000,
|
||||
},
|
||||
case: ExBudget {
|
||||
mem: 30000000000,
|
||||
cpu: 30000000000,
|
||||
mem: 100,
|
||||
cpu: 23000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ pub enum Error {
|
|||
NonPolymorphicInstantiation(Value),
|
||||
#[error("Attempted to apply a non-function:\n\n{0:#?} to argument:\n\n{1:#?}")]
|
||||
NonFunctionalApplication(Value, Value),
|
||||
#[error("Attempted to case a non-const:\n\n{0:#?}")]
|
||||
NonConstrScrutinized(Value),
|
||||
#[error("Cases: {0:#?}\n\n are missing branch for constr:\n\n{1:#?}")]
|
||||
MissingCaseBranch(Vec<Term<NamedDeBruijn>>, Value),
|
||||
#[error("Type mismatch expected '{0}' got '{1}'")]
|
||||
TypeMismatch(Type, Type),
|
||||
#[error("Type mismatch expected '(list a)' got '{0}'")]
|
||||
|
@ -36,6 +40,7 @@ pub enum Error {
|
|||
NotAConstant(Value),
|
||||
#[error("The evaluation never reached a final state")]
|
||||
MachineNeverReachedDone,
|
||||
|
||||
#[error("Decoding utf8")]
|
||||
Utf8(#[from] FromUtf8Error),
|
||||
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
|
||||
|
|
|
@ -89,8 +89,6 @@ impl BuiltinRuntime {
|
|||
}
|
||||
|
||||
pub fn push(&mut self, arg: Value) -> Result<(), Error> {
|
||||
self.fun.check_type(&arg, &self.args)?;
|
||||
|
||||
self.args.push(arg);
|
||||
|
||||
Ok(())
|
||||
|
@ -264,171 +262,6 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_type(&self, arg: &Value, args: &[Value]) -> Result<(), Error> {
|
||||
match self {
|
||||
DefaultFunction::AddInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::SubtractInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::MultiplyInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::DivideInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::QuotientInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::RemainderInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::ModInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::EqualsInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::LessThanInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::LessThanEqualsInteger => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::AppendByteString => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::ConsByteString => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Integer)
|
||||
} else {
|
||||
arg.expect_type(Type::ByteString)
|
||||
}
|
||||
}
|
||||
DefaultFunction::SliceByteString => {
|
||||
if args.len() < 2 {
|
||||
arg.expect_type(Type::Integer)
|
||||
} else {
|
||||
arg.expect_type(Type::ByteString)
|
||||
}
|
||||
}
|
||||
DefaultFunction::LengthOfByteString => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::IndexByteString => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::ByteString)
|
||||
} else {
|
||||
arg.expect_type(Type::Integer)
|
||||
}
|
||||
}
|
||||
DefaultFunction::EqualsByteString => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::LessThanByteString => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::LessThanEqualsByteString => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Sha2_256 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Sha3_256 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Blake2b_224 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Blake2b_256 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Keccak_256 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::VerifyEd25519Signature => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::VerifyEcdsaSecp256k1Signature => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::VerifySchnorrSecp256k1Signature => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::AppendString => arg.expect_type(Type::String),
|
||||
DefaultFunction::EqualsString => arg.expect_type(Type::String),
|
||||
DefaultFunction::EncodeUtf8 => arg.expect_type(Type::String),
|
||||
DefaultFunction::DecodeUtf8 => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::IfThenElse => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Bool)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
DefaultFunction::ChooseUnit => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Unit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
DefaultFunction::Trace => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::String)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
DefaultFunction::FstPair => arg.expect_pair(),
|
||||
DefaultFunction::SndPair => arg.expect_pair(),
|
||||
DefaultFunction::ChooseList => {
|
||||
if args.is_empty() {
|
||||
arg.expect_list()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
DefaultFunction::MkCons => {
|
||||
if args.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
let first = &args[0];
|
||||
|
||||
arg.expect_type(Type::List(Rc::new(first.try_into()?)))
|
||||
}
|
||||
}
|
||||
DefaultFunction::HeadList => arg.expect_list(),
|
||||
DefaultFunction::TailList => arg.expect_list(),
|
||||
DefaultFunction::NullList => arg.expect_list(),
|
||||
DefaultFunction::ChooseData => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Data)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
DefaultFunction::ConstrData => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Integer)
|
||||
} else {
|
||||
arg.expect_type(Type::List(Rc::new(Type::Data)))
|
||||
}
|
||||
}
|
||||
DefaultFunction::MapData => arg.expect_type(Type::List(Rc::new(Type::Pair(
|
||||
Rc::new(Type::Data),
|
||||
Rc::new(Type::Data),
|
||||
)))),
|
||||
DefaultFunction::ListData => arg.expect_type(Type::List(Rc::new(Type::Data))),
|
||||
DefaultFunction::IData => arg.expect_type(Type::Integer),
|
||||
DefaultFunction::BData => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::UnConstrData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::UnMapData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::UnListData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::UnIData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::UnBData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::EqualsData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::SerialiseData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::MkPairData => arg.expect_type(Type::Data),
|
||||
DefaultFunction::MkNilData => arg.expect_type(Type::Unit),
|
||||
DefaultFunction::MkNilPairData => arg.expect_type(Type::Unit),
|
||||
|
||||
DefaultFunction::Bls12_381_G1_Add => arg.expect_type(Type::Bls12_381G1Element),
|
||||
DefaultFunction::Bls12_381_G1_Neg => arg.expect_type(Type::Bls12_381G1Element),
|
||||
DefaultFunction::Bls12_381_G1_ScalarMul => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Integer)
|
||||
} else {
|
||||
arg.expect_type(Type::Bls12_381G1Element)
|
||||
}
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_Equal => arg.expect_type(Type::Bls12_381G1Element),
|
||||
DefaultFunction::Bls12_381_G1_Compress => arg.expect_type(Type::Bls12_381G1Element),
|
||||
DefaultFunction::Bls12_381_G1_Uncompress => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Bls12_381_G1_HashToGroup => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Bls12_381_G2_Add => arg.expect_type(Type::Bls12_381G2Element),
|
||||
DefaultFunction::Bls12_381_G2_Neg => arg.expect_type(Type::Bls12_381G2Element),
|
||||
DefaultFunction::Bls12_381_G2_ScalarMul => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Integer)
|
||||
} else {
|
||||
arg.expect_type(Type::Bls12_381G2Element)
|
||||
}
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Equal => arg.expect_type(Type::Bls12_381G2Element),
|
||||
DefaultFunction::Bls12_381_G2_Compress => arg.expect_type(Type::Bls12_381G2Element),
|
||||
DefaultFunction::Bls12_381_G2_Uncompress => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Bls12_381_G2_HashToGroup => arg.expect_type(Type::ByteString),
|
||||
DefaultFunction::Bls12_381_MillerLoop => {
|
||||
if args.is_empty() {
|
||||
arg.expect_type(Type::Bls12_381G1Element)
|
||||
} else {
|
||||
arg.expect_type(Type::Bls12_381G2Element)
|
||||
}
|
||||
}
|
||||
DefaultFunction::Bls12_381_MulMlResult => arg.expect_type(Type::Bls12_381MlResult),
|
||||
DefaultFunction::Bls12_381_FinalVerify => arg.expect_type(Type::Bls12_381MlResult),
|
||||
}
|
||||
}
|
||||
|
||||
// This should be safe because we've already checked
|
||||
// the types of the args as they were pushed. Although
|
||||
// the unreachables look ugly, it's the reality of the situation.
|
||||
pub fn call(
|
||||
&self,
|
||||
semantics: BuiltinSemantics,
|
||||
|
@ -437,8 +270,8 @@ impl DefaultFunction {
|
|||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
DefaultFunction::AddInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let result = arg1 + arg2;
|
||||
|
||||
|
@ -447,8 +280,8 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::SubtractInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let result = arg1 - arg2;
|
||||
|
||||
|
@ -457,8 +290,8 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::MultiplyInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let result = arg1 * arg2;
|
||||
|
||||
|
@ -467,8 +300,8 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::DivideInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
if *arg2 != 0.into() {
|
||||
let (result, _) = arg1.div_mod_floor(arg2);
|
||||
|
@ -481,8 +314,8 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::QuotientInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
if *arg2 != 0.into() {
|
||||
let (result, _) = arg1.div_rem(arg2);
|
||||
|
@ -495,8 +328,8 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::RemainderInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
if *arg2 != 0.into() {
|
||||
let (_, result) = arg1.div_rem(arg2);
|
||||
|
@ -509,8 +342,8 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::ModInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
if *arg2 != 0.into() {
|
||||
let (_, result) = arg1.div_mod_floor(arg2);
|
||||
|
@ -523,32 +356,32 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::EqualsInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let value = Value::bool(arg1 == arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::LessThanInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let value = Value::bool(arg1 < arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::LessThanEqualsInteger => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let value = Value::bool(arg1 <= arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::AppendByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
let result = arg1.iter().copied().chain(arg2.iter().copied()).collect();
|
||||
|
||||
|
@ -557,8 +390,8 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::ConsByteString => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
let byte: u8 = match semantics {
|
||||
BuiltinSemantics::V1 => {
|
||||
|
@ -584,9 +417,9 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::SliceByteString => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg3 = args[2].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
let arg3 = args[2].unwrap_byte_string()?;
|
||||
|
||||
let skip: usize = if arg1.lt(&0.into()) {
|
||||
0
|
||||
|
@ -606,15 +439,15 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::LengthOfByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let value = Value::integer(arg1.len().into());
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::IndexByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_integer();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_integer()?;
|
||||
|
||||
let index: i128 = arg2.try_into().unwrap();
|
||||
|
||||
|
@ -629,24 +462,24 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::EqualsByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
let value = Value::bool(arg1 == arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::LessThanByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
let value = Value::bool(arg1 < arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::LessThanEqualsByteString => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
let value = Value::bool(arg1 <= arg2);
|
||||
|
||||
|
@ -655,7 +488,7 @@ impl DefaultFunction {
|
|||
DefaultFunction::Sha2_256 => {
|
||||
use cryptoxide::{digest::Digest, sha2::Sha256};
|
||||
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
|
||||
|
@ -672,7 +505,7 @@ impl DefaultFunction {
|
|||
DefaultFunction::Sha3_256 => {
|
||||
use cryptoxide::{digest::Digest, sha3::Sha3_256};
|
||||
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let mut hasher = Sha3_256::new();
|
||||
|
||||
|
@ -690,7 +523,7 @@ impl DefaultFunction {
|
|||
DefaultFunction::Blake2b_224 => {
|
||||
use cryptoxide::{blake2b::Blake2b, digest::Digest};
|
||||
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let mut digest = [0u8; 28];
|
||||
let mut context = Blake2b::new(28);
|
||||
|
@ -705,7 +538,7 @@ impl DefaultFunction {
|
|||
DefaultFunction::Blake2b_256 => {
|
||||
use cryptoxide::{blake2b::Blake2b, digest::Digest};
|
||||
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let mut digest = [0u8; 32];
|
||||
let mut context = Blake2b::new(32);
|
||||
|
@ -720,7 +553,7 @@ impl DefaultFunction {
|
|||
DefaultFunction::Keccak_256 => {
|
||||
use cryptoxide::{digest::Digest, sha3::Keccak256};
|
||||
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let mut hasher = Keccak256::new();
|
||||
|
||||
|
@ -737,9 +570,9 @@ impl DefaultFunction {
|
|||
DefaultFunction::VerifyEd25519Signature => {
|
||||
use cryptoxide::ed25519;
|
||||
|
||||
let public_key = args[0].unwrap_byte_string();
|
||||
let message = args[1].unwrap_byte_string();
|
||||
let signature = args[2].unwrap_byte_string();
|
||||
let public_key = args[0].unwrap_byte_string()?;
|
||||
let message = args[1].unwrap_byte_string()?;
|
||||
let signature = args[2].unwrap_byte_string()?;
|
||||
|
||||
let public_key: [u8; 32] = public_key
|
||||
.clone()
|
||||
|
@ -758,37 +591,37 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::VerifyEcdsaSecp256k1Signature => {
|
||||
let public_key = args[0].unwrap_byte_string();
|
||||
let message = args[1].unwrap_byte_string();
|
||||
let signature = args[2].unwrap_byte_string();
|
||||
let public_key = args[0].unwrap_byte_string()?;
|
||||
let message = args[1].unwrap_byte_string()?;
|
||||
let signature = args[2].unwrap_byte_string()?;
|
||||
|
||||
verify_ecdsa(public_key, message, signature)
|
||||
}
|
||||
DefaultFunction::VerifySchnorrSecp256k1Signature => {
|
||||
let public_key = args[0].unwrap_byte_string();
|
||||
let message = args[1].unwrap_byte_string();
|
||||
let signature = args[2].unwrap_byte_string();
|
||||
let public_key = args[0].unwrap_byte_string()?;
|
||||
let message = args[1].unwrap_byte_string()?;
|
||||
let signature = args[2].unwrap_byte_string()?;
|
||||
|
||||
verify_schnorr(public_key, message, signature)
|
||||
}
|
||||
DefaultFunction::AppendString => {
|
||||
let arg1 = args[0].unwrap_string();
|
||||
let arg2 = args[1].unwrap_string();
|
||||
let arg1 = args[0].unwrap_string()?;
|
||||
let arg2 = args[1].unwrap_string()?;
|
||||
|
||||
let value = Value::string(format!("{arg1}{arg2}"));
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::EqualsString => {
|
||||
let arg1 = args[0].unwrap_string();
|
||||
let arg2 = args[1].unwrap_string();
|
||||
let arg1 = args[0].unwrap_string()?;
|
||||
let arg2 = args[1].unwrap_string()?;
|
||||
|
||||
let value = Value::bool(arg1 == arg2);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::EncodeUtf8 => {
|
||||
let arg1 = args[0].unwrap_string();
|
||||
let arg1 = args[0].unwrap_string()?;
|
||||
|
||||
let bytes = arg1.as_bytes().to_vec();
|
||||
|
||||
|
@ -797,7 +630,7 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::DecodeUtf8 => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let string = String::from_utf8(arg1.clone())?;
|
||||
|
||||
|
@ -806,7 +639,7 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::IfThenElse => {
|
||||
let condition = args[0].unwrap_bool();
|
||||
let condition = args[0].unwrap_bool()?;
|
||||
|
||||
if *condition {
|
||||
Ok(args[1].clone())
|
||||
|
@ -815,35 +648,33 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::ChooseUnit => {
|
||||
// We don't need to check it here because this is already done in
|
||||
// expect_type
|
||||
// let Value::Con(Constant::Unit) = args[0] else {unreachable!()};
|
||||
args[0].unwrap_unit()?;
|
||||
|
||||
Ok(args[1].clone())
|
||||
}
|
||||
DefaultFunction::Trace => {
|
||||
let arg1 = args[0].unwrap_string();
|
||||
let arg1 = args[0].unwrap_string()?;
|
||||
|
||||
logs.push(arg1.clone());
|
||||
|
||||
Ok(args[1].clone())
|
||||
}
|
||||
DefaultFunction::FstPair => {
|
||||
let (_, _, first, _) = args[0].unwrap_pair();
|
||||
let (_, _, first, _) = args[0].unwrap_pair()?;
|
||||
|
||||
let value = Value::Con(first.clone());
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::SndPair => {
|
||||
let (_, _, _, second) = args[0].unwrap_pair();
|
||||
let (_, _, _, second) = args[0].unwrap_pair()?;
|
||||
|
||||
let value = Value::Con(second.clone());
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::ChooseList => {
|
||||
let (_, list) = args[0].unwrap_list();
|
||||
let (_, list) = args[0].unwrap_list()?;
|
||||
|
||||
if list.is_empty() {
|
||||
Ok(args[1].clone())
|
||||
|
@ -852,8 +683,12 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::MkCons => {
|
||||
let item = args[0].unwrap_constant();
|
||||
let (r#type, list) = args[1].unwrap_list();
|
||||
let item = args[0].unwrap_constant()?;
|
||||
let (r#type, list) = args[1].unwrap_list()?;
|
||||
|
||||
if *r#type != Type::from(item) {
|
||||
return Err(Error::TypeMismatch(Type::from(item), r#type.clone()));
|
||||
}
|
||||
|
||||
let mut ret = vec![item.clone()];
|
||||
|
||||
|
@ -864,15 +699,10 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::HeadList => {
|
||||
let c @ Value::Con(inner) = &args[0] else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ProtoList(_, list) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let (_, list) = args[0].unwrap_list()?;
|
||||
|
||||
if list.is_empty() {
|
||||
Err(Error::EmptyList(c.clone()))
|
||||
Err(Error::EmptyList(args[0].clone()))
|
||||
} else {
|
||||
let value = Value::Con(list[0].clone().into());
|
||||
|
||||
|
@ -880,15 +710,10 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::TailList => {
|
||||
let c @ Value::Con(inner) = &args[0] else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ProtoList(r#type, list) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let (r#type, list) = args[0].unwrap_list()?;
|
||||
|
||||
if list.is_empty() {
|
||||
Err(Error::EmptyList(c.clone()))
|
||||
Err(Error::EmptyList(args[0].clone()))
|
||||
} else {
|
||||
let value = Value::list(r#type.clone(), list[1..].to_vec());
|
||||
|
||||
|
@ -896,27 +721,26 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
DefaultFunction::NullList => {
|
||||
let (_, list) = args[0].unwrap_list();
|
||||
let (_, list) = args[0].unwrap_list()?;
|
||||
|
||||
let value = Value::bool(list.is_empty());
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::ChooseData => {
|
||||
let con = args[0].unwrap_constant();
|
||||
let con = args[0].unwrap_data()?;
|
||||
|
||||
match con {
|
||||
Constant::Data(PlutusData::Constr(_)) => Ok(args[1].clone()),
|
||||
Constant::Data(PlutusData::Map(_)) => Ok(args[2].clone()),
|
||||
Constant::Data(PlutusData::Array(_)) => Ok(args[3].clone()),
|
||||
Constant::Data(PlutusData::BigInt(_)) => Ok(args[4].clone()),
|
||||
Constant::Data(PlutusData::BoundedBytes(_)) => Ok(args[5].clone()),
|
||||
_ => unreachable!(),
|
||||
PlutusData::Constr(_) => Ok(args[1].clone()),
|
||||
PlutusData::Map(_) => Ok(args[2].clone()),
|
||||
PlutusData::Array(_) => Ok(args[3].clone()),
|
||||
PlutusData::BigInt(_) => Ok(args[4].clone()),
|
||||
PlutusData::BoundedBytes(_) => Ok(args[5].clone()),
|
||||
}
|
||||
}
|
||||
DefaultFunction::ConstrData => {
|
||||
let i = args[0].unwrap_integer();
|
||||
let l = args[1].unwrap_data_list();
|
||||
let i = args[0].unwrap_integer()?;
|
||||
let l = args[1].unwrap_data_list()?;
|
||||
|
||||
let data_list: Vec<PlutusData> = l
|
||||
.iter()
|
||||
|
@ -939,7 +763,17 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::MapData => {
|
||||
let (_, list) = args[0].unwrap_list();
|
||||
let (r#type, list) = args[0].unwrap_list()?;
|
||||
|
||||
if *r#type != Type::Pair(Rc::new(Type::Data), Rc::new(Type::Data)) {
|
||||
return Err(Error::TypeMismatch(
|
||||
Type::List(Rc::new(Type::Pair(
|
||||
Rc::new(Type::Data),
|
||||
Rc::new(Type::Data),
|
||||
))),
|
||||
r#type.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut map = Vec::new();
|
||||
|
||||
|
@ -948,12 +782,13 @@ impl DefaultFunction {
|
|||
unreachable!()
|
||||
};
|
||||
|
||||
match (left.as_ref(), right.as_ref()) {
|
||||
(Constant::Data(key), Constant::Data(value)) => {
|
||||
map.push((key.clone(), value.clone()));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let (Constant::Data(key), Constant::Data(value)) =
|
||||
(left.as_ref(), right.as_ref())
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
map.push((key.clone(), value.clone()));
|
||||
}
|
||||
|
||||
let value = Value::data(PlutusData::Map(map.into()));
|
||||
|
@ -961,7 +796,7 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::ListData => {
|
||||
let (_, list) = args[0].unwrap_list();
|
||||
let list = args[0].unwrap_data_list()?;
|
||||
|
||||
let data_list: Vec<PlutusData> = list
|
||||
.iter()
|
||||
|
@ -976,14 +811,14 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::IData => {
|
||||
let i = args[0].unwrap_integer();
|
||||
let i = args[0].unwrap_integer()?;
|
||||
|
||||
let value = Value::data(PlutusData::BigInt(to_pallas_bigint(i)));
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::BData => {
|
||||
let b = args[0].unwrap_byte_string();
|
||||
let b = args[0].unwrap_byte_string()?;
|
||||
|
||||
let value = Value::data(PlutusData::BoundedBytes(b.clone().try_into().unwrap()));
|
||||
|
||||
|
@ -1022,10 +857,7 @@ impl DefaultFunction {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
v => Err(Error::DeserialisationError(
|
||||
"UnConstrData".to_string(),
|
||||
v.clone(),
|
||||
)),
|
||||
v => Err(Error::NotAConstant(v.clone())),
|
||||
},
|
||||
DefaultFunction::UnMapData => match &args[0] {
|
||||
v @ Value::Con(inner) => {
|
||||
|
@ -1055,10 +887,7 @@ impl DefaultFunction {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
v => Err(Error::DeserialisationError(
|
||||
"UnMapData".to_string(),
|
||||
v.clone(),
|
||||
)),
|
||||
v => Err(Error::NotAConstant(v.clone())),
|
||||
},
|
||||
DefaultFunction::UnListData => match &args[0] {
|
||||
v @ Value::Con(inner) => {
|
||||
|
@ -1079,10 +908,7 @@ impl DefaultFunction {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
v => Err(Error::DeserialisationError(
|
||||
"UnListData".to_string(),
|
||||
v.clone(),
|
||||
)),
|
||||
v => Err(Error::NotAConstant(v.clone())),
|
||||
},
|
||||
DefaultFunction::UnIData => match &args[0] {
|
||||
v @ Value::Con(inner) => {
|
||||
|
@ -1097,10 +923,7 @@ impl DefaultFunction {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
v => Err(Error::DeserialisationError(
|
||||
"UnIData".to_string(),
|
||||
v.clone(),
|
||||
)),
|
||||
v => Err(Error::NotAConstant(v.clone())),
|
||||
},
|
||||
DefaultFunction::UnBData => match &args[0] {
|
||||
v @ Value::Con(inner) => {
|
||||
|
@ -1115,34 +938,18 @@ impl DefaultFunction {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
v => Err(Error::DeserialisationError(
|
||||
"UnBData".to_string(),
|
||||
v.clone(),
|
||||
)),
|
||||
v => Err(Error::NotAConstant(v.clone())),
|
||||
},
|
||||
DefaultFunction::EqualsData => {
|
||||
let (Value::Con(inner1), Value::Con(inner2)) = (&args[0], &args[1]) else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let Constant::Data(d1) = inner1.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::Data(d2) = inner2.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let d1 = args[0].unwrap_data()?;
|
||||
let d2 = args[1].unwrap_data()?;
|
||||
|
||||
let value = Value::bool(d1.eq(d2));
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::SerialiseData => {
|
||||
let Value::Con(inner) = &args[0] else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::Data(d) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let d = args[0].unwrap_data()?;
|
||||
|
||||
let serialized_data = plutus_data_to_bytes(d).unwrap();
|
||||
|
||||
|
@ -1151,16 +958,8 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::MkPairData => {
|
||||
let (Value::Con(inner1), Value::Con(inner2)) = (&args[0], &args[1]) else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let Constant::Data(d1) = inner1.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::Data(d2) = inner2.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let d1 = args[0].unwrap_data()?;
|
||||
let d2 = args[1].unwrap_data()?;
|
||||
|
||||
let constant = Constant::ProtoPair(
|
||||
Type::Data,
|
||||
|
@ -1174,11 +973,15 @@ impl DefaultFunction {
|
|||
Ok(value)
|
||||
}
|
||||
DefaultFunction::MkNilData => {
|
||||
args[0].unwrap_unit()?;
|
||||
|
||||
let value = Value::list(Type::Data, vec![]);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
DefaultFunction::MkNilPairData => {
|
||||
args[0].unwrap_unit()?;
|
||||
|
||||
let constant = Constant::ProtoList(
|
||||
Type::Pair(Rc::new(Type::Data), Rc::new(Type::Data)),
|
||||
vec![],
|
||||
|
@ -1190,8 +993,8 @@ impl DefaultFunction {
|
|||
}
|
||||
|
||||
DefaultFunction::Bls12_381_G1_Add => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element();
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element()?;
|
||||
|
||||
let mut out = blst::blst_p1::default();
|
||||
|
||||
|
@ -1208,7 +1011,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_Neg => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element()?;
|
||||
|
||||
let mut out = *arg1;
|
||||
|
||||
|
@ -1225,8 +1028,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_ScalarMul => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element()?;
|
||||
|
||||
let size_scalar = size_of::<blst::blst_scalar>();
|
||||
|
||||
|
@ -1266,8 +1069,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_Equal => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element();
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g1_element()?;
|
||||
|
||||
let is_equal = unsafe { blst::blst_p1_is_equal(arg1, arg2) };
|
||||
|
||||
|
@ -1276,7 +1079,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_Compress => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element()?;
|
||||
|
||||
let out = arg1.compress();
|
||||
|
||||
|
@ -1285,7 +1088,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_Uncompress => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let out = blst::blst_p1::uncompress(arg1)?;
|
||||
|
||||
|
@ -1294,8 +1097,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G1_HashToGroup => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
if arg2.len() > 255 {
|
||||
return Err(Error::HashToCurveDstTooBig);
|
||||
|
@ -1321,8 +1124,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Add => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element();
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let mut out = blst::blst_p2::default();
|
||||
|
||||
|
@ -1339,7 +1142,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Neg => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let mut out = *arg1;
|
||||
|
||||
|
@ -1356,8 +1159,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_ScalarMul => {
|
||||
let arg1 = args[0].unwrap_integer();
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_integer()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let size_scalar = size_of::<blst::blst_scalar>();
|
||||
|
||||
|
@ -1397,8 +1200,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Equal => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element();
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let is_equal = unsafe { blst::blst_p2_is_equal(arg1, arg2) };
|
||||
|
||||
|
@ -1407,7 +1210,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Compress => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let out = arg1.compress();
|
||||
|
||||
|
@ -1416,7 +1219,7 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_Uncompress => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
|
||||
let out = blst::blst_p2::uncompress(arg1)?;
|
||||
|
||||
|
@ -1425,8 +1228,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_G2_HashToGroup => {
|
||||
let arg1 = args[0].unwrap_byte_string();
|
||||
let arg2 = args[1].unwrap_byte_string();
|
||||
let arg1 = args[0].unwrap_byte_string()?;
|
||||
let arg2 = args[1].unwrap_byte_string()?;
|
||||
|
||||
if arg2.len() > 255 {
|
||||
return Err(Error::HashToCurveDstTooBig);
|
||||
|
@ -1452,8 +1255,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_MillerLoop => {
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element();
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element();
|
||||
let arg1 = args[0].unwrap_bls12_381_g1_element()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_g2_element()?;
|
||||
|
||||
let mut out = blst::blst_fp12::default();
|
||||
|
||||
|
@ -1472,8 +1275,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_MulMlResult => {
|
||||
let arg1 = args[0].unwrap_bls12_381_ml_result();
|
||||
let arg2 = args[1].unwrap_bls12_381_ml_result();
|
||||
let arg1 = args[0].unwrap_bls12_381_ml_result()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_ml_result()?;
|
||||
|
||||
let mut out = blst::blst_fp12::default();
|
||||
|
||||
|
@ -1486,8 +1289,8 @@ impl DefaultFunction {
|
|||
Ok(Value::Con(constant.into()))
|
||||
}
|
||||
DefaultFunction::Bls12_381_FinalVerify => {
|
||||
let arg1 = args[0].unwrap_bls12_381_ml_result();
|
||||
let arg2 = args[1].unwrap_bls12_381_ml_result();
|
||||
let arg1 = args[0].unwrap_bls12_381_ml_result()?;
|
||||
let arg2 = args[1].unwrap_bls12_381_ml_result()?;
|
||||
|
||||
let verified = unsafe { blst::blst_fp12_finalverify(arg1, arg2) };
|
||||
|
||||
|
|
|
@ -69,125 +69,138 @@ impl Value {
|
|||
Value::Con(constant.into())
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_integer(&self) -> &BigInt {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::Integer(integer) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_integer(&self) -> Result<&BigInt, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Integer(integer) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Integer, inner.into()));
|
||||
};
|
||||
|
||||
integer
|
||||
Ok(integer)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_byte_string(&self) -> &Vec<u8> {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ByteString(byte_string) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_byte_string(&self) -> Result<&Vec<u8>, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::ByteString(byte_string) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::ByteString, inner.into()));
|
||||
};
|
||||
|
||||
byte_string
|
||||
Ok(byte_string)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_string(&self) -> &String {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::String(string) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_string(&self) -> Result<&String, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::String(string) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::String, inner.into()));
|
||||
};
|
||||
|
||||
string
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_bool(&self) -> &bool {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::Bool(condition) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_bool(&self) -> Result<&bool, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Bool(condition) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Bool, inner.into()));
|
||||
};
|
||||
|
||||
condition
|
||||
Ok(condition)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_pair(&self) -> (&Type, &Type, &Rc<Constant>, &Rc<Constant>) {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ProtoPair(t1, t2, first, second) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(super) fn unwrap_pair(
|
||||
&self,
|
||||
) -> Result<(&Type, &Type, &Rc<Constant>, &Rc<Constant>), Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::ProtoPair(t1, t2, first, second) = inner else {
|
||||
return Err(Error::PairTypeMismatch(inner.into()));
|
||||
};
|
||||
|
||||
(t1, t2, first, second)
|
||||
Ok((t1, t2, first, second))
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_list(&self) -> (&Type, &Vec<Constant>) {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ProtoList(t, list) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_list(&self) -> Result<(&Type, &Vec<Constant>), Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::ProtoList(t, list) = inner else {
|
||||
return Err(Error::ListTypeMismatch(inner.into()));
|
||||
};
|
||||
|
||||
(t, list)
|
||||
Ok((t, list))
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_constant(&self) -> &Constant {
|
||||
pub(super) fn unwrap_data(&self) -> Result<&PlutusData, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Data(data) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Data, inner.into()));
|
||||
};
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_unit(&self) -> Result<(), Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Unit = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Unit, inner.into()));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_constant(&self) -> Result<&Constant, Error> {
|
||||
let Value::Con(item) = self else {
|
||||
unreachable!()
|
||||
return Err(Error::NotAConstant(self.clone()));
|
||||
};
|
||||
|
||||
item.as_ref()
|
||||
Ok(item.as_ref())
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_data_list(&self) -> &Vec<Constant> {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
};
|
||||
let Constant::ProtoList(Type::Data, list) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_data_list(&self) -> Result<&Vec<Constant>, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::ProtoList(Type::Data, list) = inner else {
|
||||
return Err(Error::TypeMismatch(
|
||||
Type::List(Type::Data.into()),
|
||||
inner.into(),
|
||||
));
|
||||
};
|
||||
|
||||
list
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_bls12_381_g1_element(&self) -> &blst::blst_p1 {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_bls12_381_g1_element(&self) -> Result<&blst::blst_p1, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Bls12_381G1Element(element) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Bls12_381G1Element, inner.into()));
|
||||
};
|
||||
|
||||
let Constant::Bls12_381G1Element(element) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
element
|
||||
Ok(element)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_bls12_381_g2_element(&self) -> &blst::blst_p2 {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_bls12_381_g2_element(&self) -> Result<&blst::blst_p2, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Bls12_381G2Element(element) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Bls12_381G2Element, inner.into()));
|
||||
};
|
||||
|
||||
let Constant::Bls12_381G2Element(element) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
element
|
||||
Ok(element)
|
||||
}
|
||||
|
||||
pub(super) fn unwrap_bls12_381_ml_result(&self) -> &blst::blst_fp12 {
|
||||
let Value::Con(inner) = self else {
|
||||
unreachable!()
|
||||
pub(super) fn unwrap_bls12_381_ml_result(&self) -> Result<&blst::blst_fp12, Error> {
|
||||
let inner = self.unwrap_constant()?;
|
||||
|
||||
let Constant::Bls12_381MlResult(element) = inner else {
|
||||
return Err(Error::TypeMismatch(Type::Bls12_381MlResult, inner.into()));
|
||||
};
|
||||
|
||||
let Constant::Bls12_381MlResult(element) = inner.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
element
|
||||
Ok(element)
|
||||
}
|
||||
|
||||
pub fn is_integer(&self) -> bool {
|
||||
|
|
|
@ -145,7 +145,7 @@ peg::parser! {
|
|||
}
|
||||
|
||||
rule case(interner: &mut Interner) -> Term<Name>
|
||||
= "(" _* "case" _+ constr:term(interner) _* branches:(t:term(interner) _* { t })+ _* ")" {
|
||||
= "(" _* "case" _+ constr:term(interner) _* branches:(t:term(interner) _* { t })* _* ")" {
|
||||
Term::Case { constr: constr.into(), branches }
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
parse error
|
||||
parse error
|
|
@ -0,0 +1,7 @@
|
|||
(program
|
||||
1.0.0
|
||||
[
|
||||
[ (force (builtin ifThenElse)) (con string "11 <= 22") ]
|
||||
(con string "\172(11 <= 22)")
|
||||
]
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
(program 1.0.0 [
|
||||
[ (force (builtin ifThenElse)) (con string "11 <= 22") ]
|
||||
(con string "\172(11 <= 22)")
|
||||
])
|
|
@ -0,0 +1,4 @@
|
|||
-- select first branch
|
||||
(program 1.1.0
|
||||
(case (constr 0 (con integer 0)) (lam x (con integer 1)) (lam x (con integer 2)))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (con integer 1))
|
|
@ -0,0 +1,4 @@
|
|||
-- select second branch
|
||||
(program 1.1.0
|
||||
(case (constr 1 (con integer 0)) (lam x (con integer 1)) (lam x (con integer 2)))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (con integer 2))
|
|
@ -0,0 +1,4 @@
|
|||
-- select first branch and do computation with the args
|
||||
(program 1.1.0
|
||||
(case (constr 0 (con integer 3) (con integer 2)) (lam x (lam y [(builtin addInteger) x y])) (lam x (lam y [(builtin subtractInteger) x y])))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (con integer 5))
|
|
@ -0,0 +1,4 @@
|
|||
-- select second branch and do computation with the args
|
||||
(program 1.1.0
|
||||
(case (constr 1 (con integer 3) (con integer 2)) (lam x (lam y [(builtin addInteger) x y])) (lam x (lam y [(builtin subtractInteger) x y])))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (con integer 1))
|
|
@ -0,0 +1,4 @@
|
|||
-- case of non-constr
|
||||
(program 1.1.0
|
||||
(case (con integer 1) (lam x x) (lam x x))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
evaluation failure
|
|
@ -1,4 +0,0 @@
|
|||
-- case can't be used before 1.1.0
|
||||
(program 1.0.0
|
||||
(case (con integer 1))
|
||||
)
|
|
@ -1 +0,0 @@
|
|||
parse error
|
|
@ -0,0 +1,4 @@
|
|||
-- nullary case
|
||||
(program 1.1.0
|
||||
(case (constr 0) (con integer 1) (con integer 2))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (con integer 1))
|
|
@ -0,0 +1,4 @@
|
|||
-- empty case, aka -XEmptyCase
|
||||
(program 1.1.0
|
||||
(case (constr 0))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
evaluation failure
|
|
@ -0,0 +1,4 @@
|
|||
-- empty constr
|
||||
(program 1.1.0
|
||||
(constr 0 )
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (constr 0))
|
|
@ -0,0 +1,4 @@
|
|||
-- constr with an argument
|
||||
(program 1.1.0
|
||||
(constr 0 (con integer 1))
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
(program 1.1.0 (constr 0 (con integer 1)))
|
|
@ -0,0 +1,2 @@
|
|||
-- ill-typed but does not fail at runtime because the builtin application is not saturated.
|
||||
(program 1.0.0 [(builtin addInteger) (con unit ())])
|
|
@ -0,0 +1 @@
|
|||
(program 1.0.0 [ (builtin addInteger) (con unit ()) ])
|
|
@ -119,12 +119,13 @@ fn check_mint_and_outputs(
|
|||
when minted_assets is {
|
||||
[] -> True
|
||||
[(minted_asset_name, quantity), ..rest_assets] -> {
|
||||
expect True =
|
||||
expect
|
||||
list.any(
|
||||
expected_assets,
|
||||
fn(expected_asset) { expected_asset == minted_asset_name },
|
||||
)
|
||||
expect True =
|
||||
|
||||
expect
|
||||
list.any(
|
||||
outputs,
|
||||
fn(output) {
|
||||
|
@ -132,6 +133,7 @@ fn check_mint_and_outputs(
|
|||
datum == InlineDatum(minted_asset_name) && address.payment_credential == validator_cred
|
||||
},
|
||||
)
|
||||
|
||||
quantity == 1 && check_mint_and_outputs(
|
||||
rest_assets,
|
||||
outputs,
|
||||
|
|
Loading…
Reference in New Issue