Compare commits

...

10 Commits

Author SHA1 Message Date
waalge 372b186103 nix use rustc 1.79. Add analyzer to devshell 2024-06-19 15:18:18 +00:00
rvcas de870e2529
feat: warning on compiler version mismatch 2024-06-13 20:26:44 -04:00
KtorZ 0ebffa2b9e
Fix few error messages. 2024-06-13 14:54:47 +02:00
Matthias Benkort 3ddd088780
Merge pull request #955 from aiken-lang/allow-complete-patterns-in-args
Allow complete patterns in args
2024-06-07 16:10:06 +02:00
KtorZ 858dfccc82
Authorize complete patterns as function args.
This is mainly a syntactic trick/sugar, but it's been pretty annoying
  to me for a while that we can't simply pattern-match/destructure
  single-variant constructors directly from the args list. A classic
  example is when writing property tests:

  ```ak
  test foo(params via both(bytearray(), int())) {
    let (bytes, ix) = params
    ...
  }
  ```

  Now can be replaced simply with:

  ```
  test foo((bytes, ix) via both(bytearray(), int())) {
    ...
  }
  ```

  If feels natural, especially coming from the JavaScript, Haskell or
  Rust worlds and is mostly convenient. Behind the scene, the compiler
  does nothing more than re-writing the AST as the first form, with
  pre-generated arg names. Then, we fully rely on the existing
  type-checking capabilities and thus, works in a seamless way as if we
  were just pattern matching inline.
2024-06-07 15:42:25 +02:00
KtorZ b6da42baf2
Bump 'is_validator_param' up from 'ArgName' to '...Arg'
There's no reasons for this to be a property of only ArgName::Named to begin with. And now, with the extra indirection introduced for arg_name, it may leads to subtle issues when patterns args are used in validators.
2024-06-07 11:32:05 +02:00
KtorZ 4d42c6cb19
Introduce 'ArgBy' to allow defining function arg not only by name. 2024-06-07 11:17:16 +02:00
KtorZ 257bd23019
update changelog 2024-06-06 11:21:17 +02:00
KtorZ 216dab99d4
chore: Release 2024-06-06 11:19:34 +02:00
KtorZ 87f4ed359b
Update changelog: set a release date. 2024-06-06 11:19:33 +02:00
48 changed files with 1717 additions and 682 deletions

View File

@ -1,6 +1,16 @@
# Changelog # Changelog
## v1.0.29-alpha - UNRELEASED ## v1.0.30-alpha - UNRELEASED
### Added
- **aiken-lang**: also authorize (complete) patterns in function arguments list instead of only variable names. @KtorZ
### Changed
- **aiken-lang**: duplicate import lines are now automatically merged instead of raising a warning. However, imports can no longer appear anywhere in the file and must come as the first definitions. @KtorZ
## v1.0.29-alpha - 2024-06-06
### Added ### Added
@ -10,8 +20,6 @@
- **aiken-lang**: the keyword `fail` on property-based test semantic has changed and now consider a test to succeed only if **every** execution of the test failed (instead of just one). The previous behavior can be recovered by adding the keyword `once` after `fail`. @KtorZ - **aiken-lang**: the keyword `fail` on property-based test semantic has changed and now consider a test to succeed only if **every** execution of the test failed (instead of just one). The previous behavior can be recovered by adding the keyword `once` after `fail`. @KtorZ
- **aiken-lang**: duplicate import lines are now automatically merged instead of raising a warning. However, imports can no longer appear anywhere in the file and must come as the first definitions. @KtorZ
### Fixed ### Fixed
- **aiken-lang**: fixed the number of 'after x tests' number reported on property test failure, which was off by one. @KtorZ - **aiken-lang**: fixed the number of 'after x tests' number reported on property test failure, which was off by one. @KtorZ

10
Cargo.lock generated vendored
View File

@ -51,7 +51,7 @@ dependencies = [
[[package]] [[package]]
name = "aiken" name = "aiken"
version = "1.0.28-alpha" version = "1.0.29-alpha"
dependencies = [ dependencies = [
"aiken-lang", "aiken-lang",
"aiken-lsp", "aiken-lsp",
@ -77,7 +77,7 @@ dependencies = [
[[package]] [[package]]
name = "aiken-lang" name = "aiken-lang"
version = "1.0.28-alpha" version = "1.0.29-alpha"
dependencies = [ dependencies = [
"blst", "blst",
"chumsky", "chumsky",
@ -102,7 +102,7 @@ dependencies = [
[[package]] [[package]]
name = "aiken-lsp" name = "aiken-lsp"
version = "1.0.28-alpha" version = "1.0.29-alpha"
dependencies = [ dependencies = [
"aiken-lang", "aiken-lang",
"aiken-project", "aiken-project",
@ -123,7 +123,7 @@ dependencies = [
[[package]] [[package]]
name = "aiken-project" name = "aiken-project"
version = "1.0.28-alpha" version = "1.0.29-alpha"
dependencies = [ dependencies = [
"aiken-lang", "aiken-lang",
"askama", "askama",
@ -3521,7 +3521,7 @@ checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
[[package]] [[package]]
name = "uplc" name = "uplc"
version = "1.0.28-alpha" version = "1.0.29-alpha"
dependencies = [ dependencies = [
"blst", "blst",
"cryptoxide", "cryptoxide",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "aiken-lang" name = "aiken-lang"
description = "The Aiken compiler" description = "The Aiken compiler"
version = "1.0.28-alpha" version = "1.0.29-alpha"
edition = "2021" edition = "2021"
repository = "https://github.com/aiken-lang/aiken" repository = "https://github.com/aiken-lang/aiken"
homepage = "https://github.com/aiken-lang/aiken" homepage = "https://github.com/aiken-lang/aiken"
@ -25,7 +25,7 @@ pallas.workspace = true
strum = "0.24.1" strum = "0.24.1"
thiserror = "1.0.39" thiserror = "1.0.39"
vec1 = "1.10.1" vec1 = "1.10.1"
uplc = { path = '../uplc', version = "1.0.28-alpha" } uplc = { path = '../uplc', version = "1.0.29-alpha" }
num-bigint = "0.4.3" num-bigint = "0.4.3"
petgraph = "0.6.3" petgraph = "0.6.3"
blst = "0.3.11" blst = "0.3.11"

View File

@ -7,6 +7,7 @@ use crate::{
}; };
use indexmap::IndexMap; use indexmap::IndexMap;
use miette::Diagnostic; use miette::Diagnostic;
use ordinal::Ordinal;
use owo_colors::{OwoColorize, Stream::Stdout}; use owo_colors::{OwoColorize, Stream::Stdout};
use std::{ use std::{
fmt::{self, Display}, fmt::{self, Display},
@ -14,7 +15,7 @@ use std::{
rc::Rc, rc::Rc,
}; };
use uplc::machine::runtime::Compressable; use uplc::machine::runtime::Compressable;
use vec1::Vec1; use vec1::{vec1, Vec1};
pub const BACKPASS_VARIABLE: &str = "_backpass"; pub const BACKPASS_VARIABLE: &str = "_backpass";
pub const CAPTURE_VARIABLE: &str = "_capture"; pub const CAPTURE_VARIABLE: &str = "_capture";
@ -517,17 +518,17 @@ pub struct ModuleConstant<T> {
pub tipo: T, pub tipo: T,
} }
pub type TypedValidator = Validator<Rc<Type>, TypedExpr>; pub type TypedValidator = Validator<Rc<Type>, TypedArg, TypedExpr>;
pub type UntypedValidator = Validator<(), UntypedExpr>; pub type UntypedValidator = Validator<(), UntypedArg, UntypedExpr>;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Validator<T, Expr> { pub struct Validator<T, Arg, Expr> {
pub doc: Option<String>, pub doc: Option<String>,
pub end_position: usize, pub end_position: usize,
pub fun: Function<T, Expr, Arg<T>>, pub fun: Function<T, Expr, Arg>,
pub other_fun: Option<Function<T, Expr, Arg<T>>>, pub other_fun: Option<Function<T, Expr, Arg>>,
pub location: Span, pub location: Span,
pub params: Vec<Arg<T>>, pub params: Vec<Arg>,
} }
impl TypedValidator { impl TypedValidator {
@ -575,12 +576,12 @@ impl TypedValidator {
} }
} }
pub type TypedDefinition = Definition<Rc<Type>, TypedExpr, String>; pub type TypedDefinition = Definition<Rc<Type>, TypedArg, TypedExpr, String>;
pub type UntypedDefinition = Definition<(), UntypedExpr, ()>; pub type UntypedDefinition = Definition<(), UntypedArg, UntypedExpr, ()>;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Definition<T, Expr, PackageName> { pub enum Definition<T, Arg, Expr, PackageName> {
Fn(Function<T, Expr, Arg<T>>), Fn(Function<T, Expr, Arg>),
TypeAlias(TypeAlias<T>), TypeAlias(TypeAlias<T>),
@ -590,12 +591,12 @@ pub enum Definition<T, Expr, PackageName> {
ModuleConstant(ModuleConstant<T>), ModuleConstant(ModuleConstant<T>),
Test(Function<T, Expr, ArgVia<T, Expr>>), Test(Function<T, Expr, ArgVia<Arg, Expr>>),
Validator(Validator<T, Expr>), Validator(Validator<T, Arg, Expr>),
} }
impl<A, B, C> Definition<A, B, C> { impl<A, B, C, D> Definition<A, B, C, D> {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
match self { match self {
Definition::Fn(Function { location, .. }) Definition::Fn(Function { location, .. })
@ -790,27 +791,90 @@ impl<T: PartialEq> RecordConstructorArg<T> {
} }
} }
pub type TypedArg = Arg<Rc<Type>>; #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub type UntypedArg = Arg<()>; pub enum ArgBy {
ByName(ArgName),
ByPattern(UntypedPattern),
}
impl ArgBy {
pub fn into_extra_assignment(
self,
name: &ArgName,
annotation: Option<&Annotation>,
location: Span,
) -> Option<UntypedExpr> {
match self {
ArgBy::ByName(..) => None,
ArgBy::ByPattern(pattern) => Some(UntypedExpr::Assignment {
location,
value: Box::new(UntypedExpr::Var {
location,
name: name.get_name(),
}),
patterns: vec1![AssignmentPattern {
pattern,
location,
annotation: annotation.cloned(),
}],
kind: AssignmentKind::Let { backpassing: false },
}),
}
}
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Arg<T> { pub struct UntypedArg {
pub by: ArgBy,
pub location: Span,
pub annotation: Option<Annotation>,
pub doc: Option<String>,
pub is_validator_param: bool,
}
impl UntypedArg {
pub fn arg_name(&self, ix: usize) -> ArgName {
match self.by {
ArgBy::ByName(ref name) => name.clone(),
ArgBy::ByPattern(..) => {
// NOTE: We use ordinal here not only because it's cute, but because
// such a name cannot be parsed to begin with and thus, will not clash
// with any user-defined name.
let name = format!("{}_arg", Ordinal::<usize>(ix).suffix());
ArgName::Named {
label: name.clone(),
name,
location: self.location,
}
}
}
}
pub fn set_type(self, tipo: Rc<Type>, ix: usize) -> TypedArg {
TypedArg {
tipo,
arg_name: self.arg_name(ix),
location: self.location,
annotation: self.annotation,
is_validator_param: self.is_validator_param,
doc: self.doc,
}
}
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct TypedArg {
pub arg_name: ArgName, pub arg_name: ArgName,
pub location: Span, pub location: Span,
pub annotation: Option<Annotation>, pub annotation: Option<Annotation>,
pub doc: Option<String>, pub doc: Option<String>,
pub tipo: T, pub is_validator_param: bool,
pub tipo: Rc<Type>,
} }
impl<A> Arg<A> { impl TypedArg {
pub fn set_type<B>(self, tipo: B) -> Arg<B> { pub fn put_doc(&mut self, new_doc: String) {
Arg { self.doc = Some(new_doc);
tipo,
arg_name: self.arg_name,
location: self.location,
annotation: self.annotation,
doc: self.doc,
}
} }
pub fn get_variable_name(&self) -> Option<&str> { pub fn get_variable_name(&self) -> Option<&str> {
@ -830,12 +894,6 @@ impl<A> Arg<A> {
false false
} }
pub fn put_doc(&mut self, new_doc: String) {
self.doc = Some(new_doc);
}
}
impl TypedArg {
pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
if self.arg_name.location().contains(byte_index) { if self.arg_name.location().contains(byte_index) {
Some(Located::Argument(&self.arg_name, self.tipo.clone())) Some(Located::Argument(&self.arg_name, self.tipo.clone()))
@ -847,40 +905,38 @@ impl TypedArg {
} }
} }
pub type TypedArgVia = ArgVia<Rc<Type>, TypedExpr>; pub type TypedArgVia = ArgVia<TypedArg, TypedExpr>;
pub type UntypedArgVia = ArgVia<(), UntypedExpr>; pub type UntypedArgVia = ArgVia<UntypedArg, UntypedExpr>;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ArgVia<T, Expr> { pub struct ArgVia<Arg, Expr> {
pub arg_name: ArgName, pub arg: Arg,
pub location: Span,
pub via: Expr, pub via: Expr,
pub tipo: T,
pub annotation: Option<Annotation>,
} }
impl<T, Ann> From<ArgVia<T, Ann>> for Arg<T> { impl<Expr> From<ArgVia<TypedArg, Expr>> for TypedArg {
fn from(arg: ArgVia<T, Ann>) -> Arg<T> { fn from(this: ArgVia<TypedArg, Expr>) -> TypedArg {
Arg { this.arg
arg_name: arg.arg_name, }
location: arg.location, }
tipo: arg.tipo,
annotation: None, impl<Expr> From<ArgVia<UntypedArg, Expr>> for UntypedArg {
doc: None, fn from(this: ArgVia<UntypedArg, Expr>) -> UntypedArg {
} this.arg
} }
} }
impl TypedArgVia { impl TypedArgVia {
pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
if self.arg_name.location().contains(byte_index) { if self.arg.arg_name.location().contains(byte_index) {
Some(Located::Argument(&self.arg_name, self.tipo.clone())) Some(Located::Argument(&self.arg.arg_name, self.arg.tipo.clone()))
} else { } else {
// `via` is done first here because when there is no manually written // `via` is done first here because when there is no manually written
// annotation, it seems one is injected leading to a `found` returning too early // annotation, it seems one is injected leading to a `found` returning too early
// because the span of the filled in annotation matches the span of the via expr. // because the span of the filled in annotation matches the span of the via expr.
self.via.find_node(byte_index).or_else(|| { self.via.find_node(byte_index).or_else(|| {
self.annotation self.arg
.annotation
.as_ref() .as_ref()
.and_then(|annotation| annotation.find_node(byte_index)) .and_then(|annotation| annotation.find_node(byte_index))
}) })
@ -899,7 +955,6 @@ pub enum ArgName {
name: String, name: String,
label: String, label: String,
location: Span, location: Span,
is_validator_param: bool,
}, },
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, CallArg, DataTypeKey, Function, FunctionAccessKey, ModuleKind, Annotation, ArgName, CallArg, DataTypeKey, Function, FunctionAccessKey, ModuleKind,
OnTestFailure, Span, TypedDataType, TypedFunction, UnOp, OnTestFailure, Span, TypedArg, TypedDataType, TypedFunction, UnOp,
}, },
expr::TypedExpr, expr::TypedExpr,
tipo::{ tipo::{
@ -932,13 +932,13 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
function_name: "not".to_string(), function_name: "not".to_string(),
}, },
Function { Function {
arguments: vec![Arg { arguments: vec![TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "self".to_string(), name: "self".to_string(),
label: "self".to_string(), label: "self".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
doc: None, doc: None,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
@ -989,13 +989,13 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
function_name: "identity".to_string(), function_name: "identity".to_string(),
}, },
Function { Function {
arguments: vec![Arg { arguments: vec![TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "a".to_string(), name: "a".to_string(),
label: "a".to_string(), label: "a".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
@ -1045,24 +1045,25 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
Function { Function {
on_test_failure: OnTestFailure::FailImmediately, on_test_failure: OnTestFailure::FailImmediately,
arguments: vec![ arguments: vec![
Arg { TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "a".to_string(), name: "a".to_string(),
label: "a".to_string(), label: "a".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
tipo: a_var.clone(), tipo: a_var.clone(),
}, },
Arg { TypedArg {
arg_name: ArgName::Discarded { arg_name: ArgName::Discarded {
name: "_b".to_string(), name: "_b".to_string(),
label: "_b".to_string(), label: "_b".to_string(),
location: Span::empty(), location: Span::empty(),
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
@ -1122,13 +1123,13 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
}, },
Function { Function {
on_test_failure: OnTestFailure::FailImmediately, on_test_failure: OnTestFailure::FailImmediately,
arguments: vec![Arg { arguments: vec![TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "f".to_string(), name: "f".to_string(),
label: "f".to_string(), label: "f".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
@ -1139,25 +1140,25 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
tipo: return_type.clone(), tipo: return_type.clone(),
is_capture: false, is_capture: false,
args: vec![ args: vec![
Arg { TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "b".to_string(), name: "b".to_string(),
label: "b".to_string(), label: "b".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
tipo: b_var.clone(), tipo: b_var.clone(),
}, },
Arg { TypedArg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "a".to_string(), name: "a".to_string(),
label: "a".to_string(), label: "a".to_string(),
location: Span::empty(), location: Span::empty(),
is_validator_param: false,
}, },
is_validator_param: false,
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,

View File

@ -1,10 +1,11 @@
use crate::{ use crate::{
ast::{ ast::{
self, Annotation, Arg, ArgName, AssignmentPattern, BinOp, Bls12_381Point, self, Annotation, ArgBy, ArgName, AssignmentPattern, BinOp, Bls12_381Point,
ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation, ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
IfBranch, Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg, IfBranch, Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg,
RecordUpdateSpread, Span, TraceKind, TypedAssignmentKind, TypedClause, TypedDataType, RecordUpdateSpread, Span, TraceKind, TypedArg, TypedAssignmentKind, TypedClause,
TypedRecordUpdateArg, UnOp, UntypedAssignmentKind, UntypedClause, UntypedRecordUpdateArg, TypedDataType, TypedRecordUpdateArg, UnOp, UntypedArg, UntypedAssignmentKind,
UntypedClause, UntypedRecordUpdateArg,
}, },
builtins::void, builtins::void,
parser::token::Base, parser::token::Base,
@ -74,7 +75,7 @@ pub enum TypedExpr {
location: Span, location: Span,
tipo: Rc<Type>, tipo: Rc<Type>,
is_capture: bool, is_capture: bool,
args: Vec<Arg<Rc<Type>>>, args: Vec<TypedArg>,
body: Box<Self>, body: Box<Self>,
return_annotation: Option<Annotation>, return_annotation: Option<Annotation>,
}, },
@ -495,7 +496,7 @@ pub enum UntypedExpr {
Fn { Fn {
location: Span, location: Span,
fn_style: FnStyle, fn_style: FnStyle,
arguments: Vec<Arg<()>>, arguments: Vec<UntypedArg>,
body: Box<Self>, body: Box<Self>,
return_annotation: Option<Annotation>, return_annotation: Option<Annotation>,
}, },
@ -1192,17 +1193,16 @@ impl UntypedExpr {
} => { } => {
let name = format!("{}__{index}", ast::CAPTURE_VARIABLE); let name = format!("{}__{index}", ast::CAPTURE_VARIABLE);
holes.push(ast::Arg { holes.push(ast::UntypedArg {
location: Span::empty(), location: Span::empty(),
annotation: None, annotation: None,
doc: None, doc: None,
arg_name: ast::ArgName::Named { by: ArgBy::ByName(ast::ArgName::Named {
label: name.clone(), label: name.clone(),
name, name,
location: Span::empty(), location: Span::empty(),
is_validator_param: false, }),
}, is_validator_param: false,
tipo: (),
}); });
ast::CallArg { ast::CallArg {
@ -1358,12 +1358,12 @@ impl UntypedExpr {
fn_style: FnStyle::Plain, fn_style: FnStyle::Plain,
arguments: names arguments: names
.into_iter() .into_iter()
.map(|(arg_name, location, annotation)| Arg { .map(|(arg_name, location, annotation)| UntypedArg {
location, location,
doc: None, doc: None,
annotation, annotation,
tipo: (), is_validator_param: false,
arg_name, by: ArgBy::ByName(arg_name),
}) })
.collect(), .collect(),
body: Self::Sequence { body: Self::Sequence {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp, Annotation, ArgBy, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp,
ByteArrayFormatPreference, CallArg, ClauseGuard, Constant, CurveType, DataType, Definition, ByteArrayFormatPreference, CallArg, ClauseGuard, Constant, CurveType, DataType, Definition,
Function, IfBranch, LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern, Function, IfBranch, LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern,
RecordConstructor, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, RecordConstructor, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias,
@ -459,18 +459,19 @@ impl<'comments> Formatter<'comments> {
.append(line().append(self.annotation(typ)).group().nest(INDENT)) .append(line().append(self.annotation(typ)).group().nest(INDENT))
} }
fn fn_arg<'a, A>(&mut self, arg: &'a Arg<A>) -> Document<'a> { fn fn_arg<'a>(&mut self, arg: &'a UntypedArg) -> Document<'a> {
let comments = self.pop_comments(arg.location.start); let comments = self.pop_comments(arg.location.start);
let doc_comments = self.doc_comments(arg.location.start); let doc_comments = self.doc_comments(arg.location.start);
let doc = match &arg.annotation { let mut doc = match arg.by {
None => arg.arg_name.to_doc(), ArgBy::ByName(ref arg_name) => arg_name.to_doc(),
Some(a) => arg ArgBy::ByPattern(ref pattern) => self.pattern(pattern),
.arg_name };
.to_doc()
.append(": ") doc = match &arg.annotation {
.append(self.annotation(a)), None => doc,
Some(a) => doc.append(": ").append(self.annotation(a)),
} }
.group(); .group();
@ -479,21 +480,22 @@ impl<'comments> Formatter<'comments> {
commented(doc, comments) commented(doc, comments)
} }
fn fn_arg_via<'a, A>(&mut self, arg: &'a ArgVia<A, UntypedExpr>) -> Document<'a> { fn fn_arg_via<'a>(&mut self, arg_via: &'a ArgVia<UntypedArg, UntypedExpr>) -> Document<'a> {
let comments = self.pop_comments(arg.location.start); let comments = self.pop_comments(arg_via.arg.location.start);
let doc_comments = self.doc_comments(arg.location.start); let doc_comments = self.doc_comments(arg_via.arg.location.start);
let doc = match &arg.annotation { let mut doc = match arg_via.arg.by {
None => arg.arg_name.to_doc(), ArgBy::ByName(ref arg_name) => arg_name.to_doc(),
Some(a) => arg ArgBy::ByPattern(ref pattern) => self.pattern(pattern),
.arg_name };
.to_doc()
.append(": ") doc = match &arg_via.arg.annotation {
.append(self.annotation(a)), None => doc,
Some(a) => doc.append(": ").append(self.annotation(a)),
} }
.append(" via ") .append(" via ")
.append(self.expr(&arg.via, false)) .append(self.expr(&arg_via.via, false))
.group(); .group();
let doc = doc_comments.append(doc.group()).group(); let doc = doc_comments.append(doc.group()).group();

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ast, ast,
expr::UntypedExpr, expr::UntypedExpr,
parser::{annotation, error::ParseError, expr, token::Token, utils}, parser::{annotation, error::ParseError, expr, pattern, token::Token, utils},
}; };
use chumsky::prelude::*; use chumsky::prelude::*;
@ -50,40 +50,45 @@ pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Er
choice(( choice((
select! {Token::Name {name} => name} select! {Token::Name {name} => name}
.then(select! {Token::DiscardName {name} => name}) .then(select! {Token::DiscardName {name} => name})
.map_with_span(|(label, name), span| ast::ArgName::Discarded { .map_with_span(|(label, name), span| {
label, ast::ArgBy::ByName(ast::ArgName::Discarded {
name, label,
location: span, name,
location: span,
})
}), }),
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| { select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
ast::ArgName::Discarded { ast::ArgBy::ByName(ast::ArgName::Discarded {
label: name.clone(), label: name.clone(),
name, name,
location: span, location: span,
} })
}), }),
select! {Token::Name {name} => name} select! {Token::Name {name} => name}
.then(select! {Token::Name {name} => name}) .then(select! {Token::Name {name} => name})
.map_with_span(move |(label, name), span| ast::ArgName::Named { .map_with_span(|(label, name), span| {
label, ast::ArgBy::ByName(ast::ArgName::Named {
label,
name,
location: span,
})
}),
select! {Token::Name {name} => name}.map_with_span(|name, span| {
ast::ArgBy::ByName(ast::ArgName::Named {
label: name.clone(),
name, name,
location: span, location: span,
is_validator_param, })
}),
select! {Token::Name {name} => name}.map_with_span(move |name, span| ast::ArgName::Named {
label: name.clone(),
name,
location: span,
is_validator_param,
}), }),
pattern().map(ast::ArgBy::ByPattern),
)) ))
.then(just(Token::Colon).ignore_then(annotation()).or_not()) .then(just(Token::Colon).ignore_then(annotation()).or_not())
.map_with_span(|(arg_name, annotation), span| ast::Arg { .map_with_span(move |(by, annotation), span| ast::UntypedArg {
location: span, location: span,
annotation, annotation,
doc: None, doc: None,
tipo: (), is_validator_param,
arg_name, by,
}) })
} }
@ -119,4 +124,36 @@ mod tests {
"# "#
); );
} }
#[test]
fn function_by_pattern_no_annotation() {
assert_definition!(
r#"
fn foo(Foo { my_field }) {
my_field * 2
}
"#
);
}
#[test]
fn function_by_pattern_with_annotation() {
assert_definition!(
r#"
fn foo(Foo { my_field }: Foo) {
my_field * 2
}
"#
);
}
#[test]
fn function_by_pattern_with_alias() {
assert_definition!(
r#"
fn foo(Foo { my_field, .. } as x) {
my_field * x.my_other_field
}
"#
);
}
} }

View File

@ -6,34 +6,42 @@ Test(
Function { Function {
arguments: [ arguments: [
ArgVia { ArgVia {
arg_name: Named { arg: UntypedArg {
name: "x", by: ByName(
label: "x", Named {
name: "x",
label: "x",
location: 9..10,
},
),
location: 9..10, location: 9..10,
annotation: None,
doc: None,
is_validator_param: false, is_validator_param: false,
}, },
location: 9..10,
via: Var { via: Var {
location: 15..16, location: 15..16,
name: "f", name: "f",
}, },
tipo: (),
annotation: None,
}, },
ArgVia { ArgVia {
arg_name: Named { arg: UntypedArg {
name: "y", by: ByName(
label: "y", Named {
name: "y",
label: "y",
location: 18..19,
},
),
location: 18..19, location: 18..19,
annotation: None,
doc: None,
is_validator_param: false, is_validator_param: false,
}, },
location: 18..19,
via: Var { via: Var {
location: 24..25, location: 24..25,
name: "g", name: "g",
}, },
tipo: (),
annotation: None,
}, },
], ],
body: Var { body: Var {

View File

@ -6,13 +6,19 @@ Test(
Function { Function {
arguments: [ arguments: [
ArgVia { ArgVia {
arg_name: Named { arg: UntypedArg {
name: "x", by: ByName(
label: "x", Named {
name: "x",
label: "x",
location: 9..10,
},
),
location: 9..10, location: 9..10,
annotation: None,
doc: None,
is_validator_param: false, is_validator_param: false,
}, },
location: 9..10,
via: FieldAccess { via: FieldAccess {
location: 15..27, location: 15..27,
label: "any_int", label: "any_int",
@ -21,8 +27,6 @@ Test(
name: "fuzz", name: "fuzz",
}, },
}, },
tipo: (),
annotation: None,
}, },
], ],
body: Var { body: Var {

View File

@ -6,13 +6,26 @@ Test(
Function { Function {
arguments: [ arguments: [
ArgVia { ArgVia {
arg_name: Named { arg: UntypedArg {
name: "x", by: ByName(
label: "x", Named {
location: 9..10, name: "x",
label: "x",
location: 9..10,
},
),
location: 9..15,
annotation: Some(
Constructor {
location: 12..15,
module: None,
name: "Int",
arguments: [],
},
),
doc: None,
is_validator_param: false, is_validator_param: false,
}, },
location: 9..15,
via: Call { via: Call {
arguments: [], arguments: [],
fun: Var { fun: Var {
@ -21,15 +34,6 @@ Test(
}, },
location: 20..25, location: 20..25,
}, },
tipo: (),
annotation: Some(
Constructor {
location: 12..15,
module: None,
name: "Int",
arguments: [],
},
),
}, },
], ],
body: Var { body: Var {

View File

@ -8,41 +8,44 @@ Validator(
end_position: 90, end_position: 90,
fun: Function { fun: Function {
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "datum", Named {
label: "datum", name: "datum",
location: 21..26, label: "datum",
is_validator_param: false, location: 21..26,
}, },
),
location: 21..26, location: 21..26,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "rdmr", Named {
label: "rdmr", name: "rdmr",
location: 28..32, label: "rdmr",
is_validator_param: false, location: 28..32,
}, },
),
location: 28..32, location: 28..32,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "ctx", Named {
label: "ctx", name: "ctx",
location: 34..37, label: "ctx",
is_validator_param: false, location: 34..37,
}, },
),
location: 34..37, location: 34..37,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: Var { body: Var {
@ -61,29 +64,31 @@ Validator(
other_fun: Some( other_fun: Some(
Function { Function {
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "rdmr", Named {
label: "rdmr", name: "rdmr",
location: 64..68, label: "rdmr",
is_validator_param: false, location: 64..68,
}, },
),
location: 64..68, location: 64..68,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "ctx", Named {
label: "ctx", name: "ctx",
location: 70..73, label: "ctx",
is_validator_param: false, location: 70..73,
}, },
),
location: 70..73, location: 70..73,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: Var { body: Var {

View File

@ -0,0 +1,62 @@
---
source: crates/aiken-lang/src/parser/definition/function.rs
description: "Code:\n\nfn foo(Foo { my_field }) {\n my_field * 2\n}\n"
---
Fn(
Function {
arguments: [
UntypedArg {
by: ByPattern(
Constructor {
is_record: true,
location: 7..23,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 13..21,
value: Var {
location: 13..21,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: None,
tipo: (),
},
),
location: 7..23,
annotation: None,
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 31..43,
name: MultInt,
left: Var {
location: 31..39,
name: "my_field",
},
right: UInt {
location: 42..43,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
},
doc: None,
location: 0..24,
name: "foo",
public: false,
return_annotation: None,
return_type: (),
end_position: 44,
on_test_failure: FailImmediately,
},
)

View File

@ -0,0 +1,69 @@
---
source: crates/aiken-lang/src/parser/definition/function.rs
description: "Code:\n\nfn foo(Foo { my_field, .. } as x) {\n my_field * x.my_other_field\n}\n"
---
Fn(
Function {
arguments: [
UntypedArg {
by: ByPattern(
Assign {
name: "x",
location: 7..32,
pattern: Constructor {
is_record: true,
location: 7..27,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 13..21,
value: Var {
location: 13..21,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: Some(
23..25,
),
tipo: (),
},
},
),
location: 7..32,
annotation: None,
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 40..67,
name: MultInt,
left: Var {
location: 40..48,
name: "my_field",
},
right: FieldAccess {
location: 51..67,
label: "my_other_field",
container: Var {
location: 51..52,
name: "x",
},
},
},
doc: None,
location: 0..33,
name: "foo",
public: false,
return_annotation: None,
return_type: (),
end_position: 68,
on_test_failure: FailImmediately,
},
)

View File

@ -0,0 +1,69 @@
---
source: crates/aiken-lang/src/parser/definition/function.rs
description: "Code:\n\nfn foo(Foo { my_field }: Foo) {\n my_field * 2\n}\n"
---
Fn(
Function {
arguments: [
UntypedArg {
by: ByPattern(
Constructor {
is_record: true,
location: 7..23,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 13..21,
value: Var {
location: 13..21,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: None,
tipo: (),
},
),
location: 7..28,
annotation: Some(
Constructor {
location: 25..28,
module: None,
name: "Foo",
arguments: [],
},
),
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 36..48,
name: MultInt,
left: Var {
location: 36..44,
name: "my_field",
},
right: UInt {
location: 47..48,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
},
doc: None,
location: 0..29,
name: "foo",
public: false,
return_annotation: None,
return_type: (),
end_position: 49,
on_test_failure: FailImmediately,
},
)

View File

@ -8,41 +8,44 @@ Validator(
end_position: 54, end_position: 54,
fun: Function { fun: Function {
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "datum", Named {
label: "datum", name: "datum",
location: 21..26, label: "datum",
is_validator_param: false, location: 21..26,
}, },
),
location: 21..26, location: 21..26,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "rdmr", Named {
label: "rdmr", name: "rdmr",
location: 28..32, label: "rdmr",
is_validator_param: false, location: 28..32,
}, },
),
location: 28..32, location: 28..32,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "ctx", Named {
label: "ctx", name: "ctx",
location: 34..37, label: "ctx",
is_validator_param: false, location: 34..37,
}, },
),
location: 34..37, location: 34..37,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: Var { body: Var {

View File

@ -7,6 +7,7 @@ use crate::{
chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain}, chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain},
error::ParseError, error::ParseError,
expr::{self, bytearray, int as uint, list, string, tuple, var}, expr::{self, bytearray, int as uint, list, string, tuple, var},
pattern,
token::Token, token::Token,
}, },
}; };
@ -54,31 +55,34 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> { pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> {
choice(( choice((
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| { select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
ast::ArgName::Discarded { ast::ArgBy::ByName(ast::ArgName::Discarded {
label: name.clone(), label: name.clone(),
name, name,
location: span, location: span,
} })
}), }),
select! {Token::Name {name} => name}.map_with_span(move |name, location| { select! {Token::Name {name} => name}.map_with_span(|name, location| {
ast::ArgName::Named { ast::ArgBy::ByName(ast::ArgName::Named {
label: name.clone(), label: name.clone(),
name, name,
location, location,
is_validator_param: false, })
}
}), }),
pattern().map(ast::ArgBy::ByPattern),
)) ))
.then(just(Token::Colon).ignore_then(annotation()).or_not()) .then(just(Token::Colon).ignore_then(annotation()).or_not())
.map_with_span(|(arg_name, annotation), location| (arg_name, annotation, location)) .map_with_span(|(arg_name, annotation), location| (arg_name, annotation, location))
.then_ignore(just(Token::Via)) .then_ignore(just(Token::Via))
.then(fuzzer()) .then(fuzzer())
.map(|((arg_name, annotation, location), via)| ast::ArgVia { .map(|((by, annotation, location), via)| ast::ArgVia {
arg_name, arg: ast::UntypedArg {
by,
annotation,
location,
doc: None,
is_validator_param: false,
},
via, via,
annotation,
tipo: (),
location,
}) })
} }

View File

@ -1,10 +1,9 @@
use chumsky::prelude::*;
use crate::{ use crate::{
ast, ast,
expr::{FnStyle, UntypedExpr}, expr::{FnStyle, UntypedExpr},
parser::{error::ParseError, token::Token}, parser::{error::ParseError, token::Token},
}; };
use chumsky::prelude::*;
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> { pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
select! { select! {
@ -41,29 +40,27 @@ pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
}; };
let arguments = vec![ let arguments = vec![
ast::Arg { ast::UntypedArg {
arg_name: ast::ArgName::Named { by: ast::ArgBy::ByName(ast::ArgName::Named {
name: "left".to_string(), name: "left".to_string(),
label: "left".to_string(), label: "left".to_string(),
location, location,
is_validator_param: false, }),
}, is_validator_param: false,
annotation: arg_annotation.clone(), annotation: arg_annotation.clone(),
doc: None, doc: None,
location, location,
tipo: (),
}, },
ast::Arg { ast::UntypedArg {
arg_name: ast::ArgName::Named { by: ast::ArgBy::ByName(ast::ArgName::Named {
name: "right".to_string(), name: "right".to_string(),
label: "right".to_string(), label: "right".to_string(),
location, location,
is_validator_param: false, }),
}, is_validator_param: false,
annotation: arg_annotation, annotation: arg_annotation,
doc: None, doc: None,
location, location,
tipo: (),
}, },
]; ];

View File

@ -1,10 +1,9 @@
use chumsky::prelude::*;
use crate::{ use crate::{
ast, ast,
expr::{FnStyle, UntypedExpr}, expr::{FnStyle, UntypedExpr},
parser::{annotation, error::ParseError, token::Token}, parser::{annotation, error::ParseError, pattern, token::Token},
}; };
use chumsky::prelude::*;
pub fn parser( pub fn parser(
sequence: Recursive<'_, Token, UntypedExpr, ParseError>, sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
@ -33,26 +32,28 @@ pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
// TODO: return a better error when a label is provided `UnexpectedLabel` // TODO: return a better error when a label is provided `UnexpectedLabel`
choice(( choice((
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| { select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
ast::ArgName::Discarded { ast::ArgBy::ByName(ast::ArgName::Discarded {
label: name.clone(), label: name.clone(),
name, name,
location: span, location: span,
} })
}), }),
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named { select! {Token::Name {name} => name}.map_with_span(|name, span| {
label: name.clone(), ast::ArgBy::ByName(ast::ArgName::Named {
name, label: name.clone(),
location: span, name,
is_validator_param: false, location: span,
})
}), }),
pattern().map(ast::ArgBy::ByPattern),
)) ))
.then(just(Token::Colon).ignore_then(annotation()).or_not()) .then(just(Token::Colon).ignore_then(annotation()).or_not())
.map_with_span(|(arg_name, annotation), span| ast::Arg { .map_with_span(|(by, annotation), span| ast::UntypedArg {
is_validator_param: false,
location: span, location: span,
annotation, annotation,
doc: None, doc: None,
tipo: (), by,
arg_name,
}) })
} }
@ -64,4 +65,19 @@ mod tests {
fn anonymous_function_basic() { fn anonymous_function_basic() {
assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#); assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
} }
#[test]
fn anonymous_function_by_pattern_no_annotation() {
assert_expr!(r#"fn (Foo { my_field }) { my_field * 2 }"#);
}
#[test]
fn anonymous_function_by_pattern_with_annotation() {
assert_expr!(r#"fn (Foo { my_field } : Foo) { my_field * 2 }"#);
}
#[test]
fn anonymous_function_by_pattern_with_alias() {
assert_expr!(r#"fn (Foo { my_field, .. } as x) { my_field * my_other_field }"#);
}
} }

View File

@ -6,13 +6,14 @@ Fn {
location: 0..28, location: 0..28,
fn_style: Plain, fn_style: Plain,
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "a", Named {
label: "a", name: "a",
location: 4..5, label: "a",
is_validator_param: false, location: 4..5,
}, },
),
location: 4..10, location: 4..10,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -23,7 +24,7 @@ Fn {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {

View File

@ -0,0 +1,77 @@
---
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
description: "Code:\n\nfn (a: Int) -> Int {\n let b = 1\n a + b\n}"
---
Fn {
location: 0..46,
fn_style: Plain,
arguments: [
Arg {
arg_name: Named {
name: "a",
label: "a",
location: 4..5,
is_validator_param: false,
},
location: 4..10,
annotation: Some(
Constructor {
location: 7..10,
module: None,
name: "Int",
arguments: [],
},
),
doc: None,
tipo: (),
},
],
body: Sequence {
location: 39..44,
expressions: [
Assignment {
location: 25..34,
value: UInt {
location: 33..34,
value: "1",
base: Decimal {
numeric_underscore: false,
},
},
patterns: [
AssignmentPattern {
pattern: Var {
location: 29..30,
name: "b",
},
annotation: None,
location: 29..30,
},
],
kind: Let {
backpassing: false,
},
},
BinOp {
location: 39..44,
name: AddInt,
left: Var {
location: 39..40,
name: "a",
},
right: Var {
location: 43..44,
name: "b",
},
},
],
},
return_annotation: Some(
Constructor {
location: 15..18,
module: None,
name: "Int",
arguments: [],
},
),
}

View File

@ -0,0 +1,55 @@
---
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
description: "Code:\n\nfn (Foo { my_field }) { my_field * 2 }"
---
Fn {
location: 0..38,
fn_style: Plain,
arguments: [
UntypedArg {
by: ByPattern(
Constructor {
is_record: true,
location: 4..20,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 10..18,
value: Var {
location: 10..18,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: None,
tipo: (),
},
),
location: 4..20,
annotation: None,
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 24..36,
name: MultInt,
left: Var {
location: 24..32,
name: "my_field",
},
right: UInt {
location: 35..36,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
},
return_annotation: None,
}

View File

@ -0,0 +1,58 @@
---
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
description: "Code:\n\nfn (Foo { my_field, .. } as x) { my_field * my_other_field }"
---
Fn {
location: 0..60,
fn_style: Plain,
arguments: [
UntypedArg {
by: ByPattern(
Assign {
name: "x",
location: 4..29,
pattern: Constructor {
is_record: true,
location: 4..24,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 10..18,
value: Var {
location: 10..18,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: Some(
20..22,
),
tipo: (),
},
},
),
location: 4..29,
annotation: None,
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 33..58,
name: MultInt,
left: Var {
location: 33..41,
name: "my_field",
},
right: Var {
location: 44..58,
name: "my_other_field",
},
},
return_annotation: None,
}

View File

@ -0,0 +1,62 @@
---
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
description: "Code:\n\nfn (Foo { my_field } : Foo) { my_field * 2 }"
---
Fn {
location: 0..44,
fn_style: Plain,
arguments: [
UntypedArg {
by: ByPattern(
Constructor {
is_record: true,
location: 4..20,
name: "Foo",
arguments: [
CallArg {
label: Some(
"my_field",
),
location: 10..18,
value: Var {
location: 10..18,
name: "my_field",
},
},
],
module: None,
constructor: (),
spread_location: None,
tipo: (),
},
),
location: 4..26,
annotation: Some(
Constructor {
location: 23..26,
module: None,
name: "Foo",
arguments: [],
},
),
doc: None,
is_validator_param: false,
},
],
body: BinOp {
location: 30..42,
name: MultInt,
left: Var {
location: 30..38,
name: "my_field",
},
right: UInt {
location: 41..42,
value: "2",
base: Decimal {
numeric_underscore: false,
},
},
},
return_annotation: None,
}

View File

@ -24,13 +24,14 @@ Sequence {
GtInt, GtInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 16..17, label: "left",
is_validator_param: false, location: 16..17,
}, },
),
location: 16..17, location: 16..17,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -41,15 +42,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 16..17, label: "right",
is_validator_param: false, location: 16..17,
}, },
),
location: 16..17, location: 16..17,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -60,7 +62,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -119,13 +121,14 @@ Sequence {
GtEqInt, GtEqInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 38..40, label: "left",
is_validator_param: false, location: 38..40,
}, },
),
location: 38..40, location: 38..40,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -136,15 +139,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 38..40, label: "right",
is_validator_param: false, location: 38..40,
}, },
),
location: 38..40, location: 38..40,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -155,7 +159,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -214,13 +218,14 @@ Sequence {
LtInt, LtInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 61..62, label: "left",
is_validator_param: false, location: 61..62,
}, },
),
location: 61..62, location: 61..62,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -231,15 +236,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 61..62, label: "right",
is_validator_param: false, location: 61..62,
}, },
),
location: 61..62, location: 61..62,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -250,7 +256,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -309,13 +315,14 @@ Sequence {
LtEqInt, LtEqInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 83..85, label: "left",
is_validator_param: false, location: 83..85,
}, },
),
location: 83..85, location: 83..85,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -326,15 +333,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 83..85, label: "right",
is_validator_param: false, location: 83..85,
}, },
),
location: 83..85, location: 83..85,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -345,7 +353,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -404,29 +412,31 @@ Sequence {
Eq, Eq,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 106..108, label: "left",
is_validator_param: false, location: 106..108,
}, },
),
location: 106..108, location: 106..108,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 106..108, label: "right",
is_validator_param: false, location: 106..108,
}, },
),
location: 106..108, location: 106..108,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -485,29 +495,31 @@ Sequence {
NotEq, NotEq,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 129..131, label: "left",
is_validator_param: false, location: 129..131,
}, },
),
location: 129..131, location: 129..131,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 129..131, label: "right",
is_validator_param: false, location: 129..131,
}, },
),
location: 129..131, location: 129..131,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -566,13 +578,14 @@ Sequence {
And, And,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 152..154, label: "left",
is_validator_param: false, location: 152..154,
}, },
),
location: 152..154, location: 152..154,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -583,15 +596,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 152..154, label: "right",
is_validator_param: false, location: 152..154,
}, },
),
location: 152..154, location: 152..154,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -602,7 +616,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -661,13 +675,14 @@ Sequence {
Or, Or,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 175..177, label: "left",
is_validator_param: false, location: 175..177,
}, },
),
location: 175..177, location: 175..177,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -678,15 +693,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 175..177, label: "right",
is_validator_param: false, location: 175..177,
}, },
),
location: 175..177, location: 175..177,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -697,7 +713,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -756,13 +772,14 @@ Sequence {
AddInt, AddInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 198..199, label: "left",
is_validator_param: false, location: 198..199,
}, },
),
location: 198..199, location: 198..199,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -773,15 +790,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 198..199, label: "right",
is_validator_param: false, location: 198..199,
}, },
),
location: 198..199, location: 198..199,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -792,7 +810,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -851,13 +869,14 @@ Sequence {
SubInt, SubInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 220..221, label: "left",
is_validator_param: false, location: 220..221,
}, },
),
location: 220..221, location: 220..221,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -868,15 +887,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 220..221, label: "right",
is_validator_param: false, location: 220..221,
}, },
),
location: 220..221, location: 220..221,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -887,7 +907,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -946,13 +966,14 @@ Sequence {
DivInt, DivInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 242..243, label: "left",
is_validator_param: false, location: 242..243,
}, },
),
location: 242..243, location: 242..243,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -963,15 +984,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 242..243, label: "right",
is_validator_param: false, location: 242..243,
}, },
),
location: 242..243, location: 242..243,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -982,7 +1004,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -1041,13 +1063,14 @@ Sequence {
MultInt, MultInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 264..265, label: "left",
is_validator_param: false, location: 264..265,
}, },
),
location: 264..265, location: 264..265,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -1058,15 +1081,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 264..265, label: "right",
is_validator_param: false, location: 264..265,
}, },
),
location: 264..265, location: 264..265,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -1077,7 +1101,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {
@ -1136,13 +1160,14 @@ Sequence {
ModInt, ModInt,
), ),
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "left", Named {
label: "left", name: "left",
location: 286..287, label: "left",
is_validator_param: false, location: 286..287,
}, },
),
location: 286..287, location: 286..287,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -1153,15 +1178,16 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "right", Named {
label: "right", name: "right",
location: 286..287, label: "right",
is_validator_param: false, location: 286..287,
}, },
),
location: 286..287, location: 286..287,
annotation: Some( annotation: Some(
Constructor { Constructor {
@ -1172,7 +1198,7 @@ Sequence {
}, },
), ),
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {

View File

@ -47,17 +47,18 @@ Sequence {
location: 36..65, location: 36..65,
fn_style: Capture, fn_style: Capture,
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "_capture__0", Named {
label: "_capture__0", name: "_capture__0",
location: 0..0, label: "_capture__0",
is_validator_param: false, location: 0..0,
}, },
),
location: 0..0, location: 0..0,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: Call { body: Call {
@ -77,17 +78,18 @@ Sequence {
location: 48..64, location: 48..64,
fn_style: Plain, fn_style: Plain,
arguments: [ arguments: [
Arg { UntypedArg {
arg_name: Named { by: ByName(
name: "y", Named {
label: "y", name: "y",
location: 52..53, label: "y",
is_validator_param: false, location: 52..53,
}, },
),
location: 52..53, location: 52..53,
annotation: None, annotation: None,
doc: None, doc: None,
tipo: (), is_validator_param: false,
}, },
], ],
body: BinOp { body: BinOp {

View File

@ -2539,3 +2539,37 @@ fn mutually_recursive_1() {
assert!(check(parse(source_code)).is_ok()); assert!(check(parse(source_code)).is_ok());
} }
#[test]
fn fn_single_variant_pattern() {
let source_code = r#"
pub type Foo {
a: Int
}
pub fn foo(Foo { a }) {
a + 1
}
"#;
assert!(dbg!(check(parse(source_code))).is_ok());
}
#[test]
fn fn_multi_variant_pattern() {
let source_code = r#"
type Foo {
A { a: Int }
B { b: Int }
}
pub fn foo(A { a }) {
a + 1
}
"#;
assert!(matches!(
dbg!(check_validator(parse(source_code))),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}

View File

@ -883,3 +883,68 @@ fn format_pairs() {
}"# }"#
); );
} }
#[test]
fn format_fn_pattern() {
assert_format!(
r#"
pub fn foo(Foo { a, b, .. }) {
todo
}
pub fn bar([Bar] : List<Bar>) {
todo
}
pub fn baz((Baz, Baz) as x) {
todo
}
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
test buz((a, b) via some_fuzzer()) {
todo
}
"#
);
}
#[test]
fn format_anon_fn_pattern() {
assert_format!(
r#"
pub fn main() {
let foo = fn (Foo { a, b, .. }) { todo }
let bar = fn ([Bar] : List<Bar>) { todo }
let baz = fn ((Baz, Baz) as x) { todo }
let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }
todo
}
"#
);
}
#[test]
fn format_validator_pattern() {
assert_format!(
r#"
validator(Foo { a, b, .. }) {
fn foo() { todo }
}
validator([Bar] : List<Bar>) {
fn bar() { todo }
}
validator((Baz, Baz) as x) {
fn baz() { todo }
}
validator((fst, snd) as x: Pair<Int, Int>) {
fn fiz() { todo }
}
"#
);
}

View File

@ -0,0 +1,23 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\npub fn main() {\n let foo = fn (Foo { a, b, .. }) { todo }\n let bar = fn ([Bar] : List<Bar>) { todo }\n let baz = fn ((Baz, Baz) as x) { todo }\n let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }\n todo\n}\n"
---
pub fn main() {
let foo =
fn(Foo { a, b, .. }) {
todo
}
let bar =
fn([Bar]: List<Bar>) {
todo
}
let baz =
fn((Baz, Baz) as x) {
todo
}
let fiz =
fn(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
todo
}

View File

@ -0,0 +1,23 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\npub fn foo(Foo { a, b, .. }) {\n todo\n}\n\npub fn bar([Bar] : List<Bar>) {\n todo\n}\n\npub fn baz((Baz, Baz) as x) {\n todo\n}\n\npub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {\n todo\n}\n\ntest buz((a, b) via some_fuzzer()) {\n todo\n}\n"
---
pub fn foo(Foo { a, b, .. }) {
todo
}
pub fn bar([Bar]: List<Bar>) {
todo
}
pub fn baz((Baz, Baz) as x) {
todo
}
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
test buz((a, b) via some_fuzzer()) {
todo
}

View File

@ -0,0 +1,27 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\nvalidator(Foo { a, b, .. }) {\n fn foo() { todo }\n}\n\nvalidator([Bar] : List<Bar>) {\n fn bar() { todo }\n}\n\nvalidator((Baz, Baz) as x) {\n fn baz() { todo }\n}\n\nvalidator((fst, snd) as x: Pair<Int, Int>) {\n fn fiz() { todo }\n}\n"
---
validator(Foo { a, b, .. }) {
fn foo() {
todo
}
}
validator([Bar]: List<Bar>) {
fn bar() {
todo
}
}
validator((Baz, Baz) as x) {
fn baz() {
todo
}
}
validator((fst, snd) as x: Pair<Int, Int>) {
fn fiz() {
todo
}
}

View File

@ -1149,7 +1149,7 @@ impl<'a> Environment<'a> {
let mut field_map = FieldMap::new(arguments.len(), true); let mut field_map = FieldMap::new(arguments.len(), true);
for (i, arg) in arguments.iter().enumerate() { for (i, arg) in arguments.iter().enumerate() {
field_map.insert(arg.arg_name.get_label(), i, &arg.location)?; field_map.insert(arg.arg_name(i).get_label(), i, &arg.location)?;
} }
let field_map = field_map.into_option(); let field_map = field_map.into_option();

View File

@ -537,7 +537,7 @@ If you really meant to return that last expression, try to replace it with the f
}, },
#[error("{}\n", if *is_let { #[error("{}\n", if *is_let {
"I noticed a let assignment matching a value with more than one pattern.".to_string() "I noticed an incomplete single-pattern matching a value with more than one pattern.".to_string()
} else { } else {
format!( format!(
"I realized that a given '{keyword_when}/{keyword_is}' expression is non-exhaustive.", "I realized that a given '{keyword_when}/{keyword_is}' expression is non-exhaustive.",
@ -1696,15 +1696,15 @@ pub enum Warning {
#[error( #[error(
"I came across a validator in a {} {}", "I came across a validator in a {} {}",
"lib/".if_supports_color(Stderr, |s| s.purple()), "lib/".if_supports_color(Stderr, |s| s.purple()),
"module which means\nI'm going to ignore it.\n".if_supports_color(Stderr, |s| s.yellow()), "module which means I'm going to ignore it.".if_supports_color(Stderr, |s| s.yellow()),
)] )]
#[diagnostic(help( #[diagnostic(help(
"No big deal, but you might want to move it to a {} module\nor remove it to get rid of that warning.", "No big deal, but you might want to move it to the {} folder or remove it to get rid of that warning.",
"validators/".if_supports_color(Stderr, |s| s.purple()) "validators".if_supports_color(Stderr, |s| s.purple()),
))] ))]
#[diagnostic(code("unused::validator"))] #[diagnostic(code("unused::validator"))]
ValidatorInLibraryModule { ValidatorInLibraryModule {
#[label("unused validator")] #[label("ignored")]
location: Span, location: Span,
}, },

View File

@ -10,7 +10,7 @@ use super::{
}; };
use crate::{ use crate::{
ast::{ ast::{
self, Annotation, Arg, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point, self, Annotation, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
ByteArrayFormatPreference, CallArg, ClauseGuard, Constant, Curve, Function, IfBranch, ByteArrayFormatPreference, CallArg, ClauseGuard, Constant, Curve, Function, IfBranch,
LogicalOpChainKind, Pattern, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing, LogicalOpChainKind, Pattern, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing,
TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedPattern, TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedPattern,
@ -59,6 +59,39 @@ pub(crate) fn infer_function(
return_type: _, return_type: _,
} = fun; } = fun;
let mut extra_let_assignments = Vec::new();
for (i, arg) in arguments.iter().enumerate() {
let let_assignment = arg.by.clone().into_extra_assignment(
&arg.arg_name(i),
arg.annotation.as_ref(),
arg.location,
);
match let_assignment {
None => {}
Some(expr) => extra_let_assignments.push(expr),
}
}
let sequence;
let body = if extra_let_assignments.is_empty() {
body
} else if let UntypedExpr::Sequence { expressions, .. } = body {
extra_let_assignments.extend(expressions.clone());
sequence = UntypedExpr::Sequence {
expressions: extra_let_assignments,
location: *location,
};
&sequence
} else {
extra_let_assignments.extend([body.clone()]);
sequence = UntypedExpr::Sequence {
expressions: extra_let_assignments,
location: body.location(),
};
&sequence
};
let preregistered_fn = environment let preregistered_fn = environment
.get_variable(name) .get_variable(name)
.expect("Could not find preregistered type for function"); .expect("Could not find preregistered type for function");
@ -79,7 +112,8 @@ pub(crate) fn infer_function(
let arguments = arguments let arguments = arguments
.iter() .iter()
.zip(&args_types) .zip(&args_types)
.map(|(arg_name, tipo)| arg_name.to_owned().set_type(tipo.clone())) .enumerate()
.map(|(ix, (arg_name, tipo))| arg_name.to_owned().set_type(tipo.clone(), ix))
.collect(); .collect();
let hydrator = hydrators let hydrator = hydrators
@ -330,9 +364,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let mut arguments = Vec::new(); let mut arguments = Vec::new();
let mut extra_let_assignments = Vec::new();
for (i, arg) in args.into_iter().enumerate() { for (i, arg) in args.into_iter().enumerate() {
let arg = self.infer_param(arg, expected_args.get(i).cloned())?; let (arg, extra_let_assignment) =
self.infer_param(arg, expected_args.get(i).cloned(), i)?;
if let Some(expr) = extra_let_assignment {
extra_let_assignments.push(expr);
}
arguments.push(arg); arguments.push(arg);
} }
@ -341,6 +379,28 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
None => None, None => None,
}; };
let body_location = body.location();
let body = if extra_let_assignments.is_empty() {
body
} else if let UntypedExpr::Sequence {
location,
expressions,
} = body
{
extra_let_assignments.extend(expressions);
UntypedExpr::Sequence {
expressions: extra_let_assignments,
location,
}
} else {
extra_let_assignments.extend([body]);
UntypedExpr::Sequence {
expressions: extra_let_assignments,
location: body_location,
}
};
self.infer_fn_with_known_types(arguments, body, return_type) self.infer_fn_with_known_types(arguments, body, return_type)
} }
@ -1072,16 +1132,19 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
fn infer_param( fn infer_param(
&mut self, &mut self,
arg: UntypedArg, untyped_arg: UntypedArg,
expected: Option<Rc<Type>>, expected: Option<Rc<Type>>,
) -> Result<TypedArg, Error> { ix: usize,
let Arg { ) -> Result<(TypedArg, Option<UntypedExpr>), Error> {
arg_name, let arg_name = untyped_arg.arg_name(ix);
let UntypedArg {
by,
annotation, annotation,
location, location,
doc, doc,
tipo: _, is_validator_param,
} = arg; } = untyped_arg;
let tipo = annotation let tipo = annotation
.clone() .clone()
@ -1097,13 +1160,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.unify(expected, tipo.clone(), location, false)?; self.unify(expected, tipo.clone(), location, false)?;
} }
Ok(Arg { let extra_assignment = by.into_extra_assignment(&arg_name, annotation.as_ref(), location);
let typed_arg = TypedArg {
arg_name, arg_name,
location, location,
annotation, annotation,
tipo, tipo,
is_validator_param,
doc, doc,
}) };
Ok((typed_arg, extra_assignment))
} }
fn infer_assignment( fn infer_assignment(
@ -1733,12 +1801,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
for arg in &args { for arg in &args {
match &arg.arg_name { match &arg.arg_name {
ArgName::Named { ArgName::Named { name, location, .. } if !arg.is_validator_param => {
name,
is_validator_param,
location,
..
} if !is_validator_param => {
if let Some(duplicate_location) = argument_names.insert(name, location) { if let Some(duplicate_location) = argument_names.insert(name, location) {
return Err(Error::DuplicateArgument { return Err(Error::DuplicateArgument {
location: *location, location: *location,
@ -1965,7 +2028,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
label: name.clone(), label: name.clone(),
name, name,
location: var_location, location: var_location,
is_validator_param: false,
}; };
names.push((name, assignment_pattern_location, annotation)); names.push((name, assignment_pattern_location, annotation));
@ -1989,7 +2051,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
label: name.clone(), label: name.clone(),
name: name.clone(), name: name.clone(),
location: pattern.location(), location: pattern.location(),
is_validator_param: false,
}; };
let pattern_is_var = pattern.is_var(); let pattern_is_var = pattern.is_var();

View File

@ -7,8 +7,8 @@ use super::{
}; };
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind,
ModuleKind, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedDefinition, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition,
TypedFunction, TypedModule, UntypedDefinition, UntypedModule, Use, Validator, TypedFunction, TypedModule, UntypedDefinition, UntypedModule, Use, Validator,
}, },
builtins, builtins,
@ -198,14 +198,17 @@ fn infer_definition(
.function_types() .function_types()
.expect("Preregistered type for fn was not a fn"); .expect("Preregistered type for fn was not a fn");
for (arg, t) in params.iter().zip(args_types[0..params.len()].iter()) { for (ix, (arg, t)) in params
match &arg.arg_name { .iter()
.zip(args_types[0..params.len()].iter())
.enumerate()
{
match &arg.arg_name(ix) {
ArgName::Named { ArgName::Named {
name, name,
is_validator_param,
label: _, label: _,
location: _, location: _,
} if *is_validator_param => { } if arg.is_validator_param => {
environment.insert_variable( environment.insert_variable(
name.to_string(), name.to_string(),
ValueConstructorVariant::LocalVariable { ValueConstructorVariant::LocalVariable {
@ -326,7 +329,12 @@ fn infer_definition(
if f.arguments.len() > 1 { if f.arguments.len() > 1 {
return Err(Error::IncorrectTestArity { return Err(Error::IncorrectTestArity {
count: f.arguments.len(), count: f.arguments.len(),
location: f.arguments.get(1).expect("arguments.len() > 1").location, location: f
.arguments
.get(1)
.expect("arguments.len() > 1")
.arg
.location,
}); });
} }
@ -336,6 +344,7 @@ fn infer_definition(
let hydrator: &mut Hydrator = hydrators.get_mut(&f.name).unwrap(); let hydrator: &mut Hydrator = hydrators.get_mut(&f.name).unwrap();
let provided_inner_type = arg let provided_inner_type = arg
.arg
.annotation .annotation
.as_ref() .as_ref()
.map(|ann| hydrator.type_from_annotation(ann, environment)) .map(|ann| hydrator.type_from_annotation(ann, environment))
@ -352,13 +361,14 @@ fn infer_definition(
// Fuzzer. // Fuzzer.
if let Some(provided_inner_type) = provided_inner_type { if let Some(provided_inner_type) = provided_inner_type {
if !arg if !arg
.arg
.annotation .annotation
.as_ref() .as_ref()
.unwrap() .unwrap()
.is_logically_equal(&inferred_annotation) .is_logically_equal(&inferred_annotation)
{ {
return Err(Error::CouldNotUnify { return Err(Error::CouldNotUnify {
location: arg.location, location: arg.arg.location,
expected: inferred_inner_type.clone(), expected: inferred_inner_type.clone(),
given: provided_inner_type.clone(), given: provided_inner_type.clone(),
situation: Some(UnifyErrorSituation::FuzzerAnnotationMismatch), situation: Some(UnifyErrorSituation::FuzzerAnnotationMismatch),
@ -417,23 +427,17 @@ fn infer_definition(
public: typed_f.public, public: typed_f.public,
arguments: match typed_via { arguments: match typed_via {
Some((via, tipo)) => { Some((via, tipo)) => {
let Arg { let arg = typed_f
arg_name,
location,
annotation: _,
doc: _,
tipo: _,
} = typed_f
.arguments .arguments
.first() .first()
.expect("has exactly one argument") .expect("has exactly one argument")
.to_owned(); .to_owned();
vec![ArgVia { vec![ArgVia {
annotation, arg: TypedArg {
arg_name, tipo,
location, annotation,
tipo, ..arg
},
via, via,
}] }]
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "aiken-lsp" name = "aiken-lsp"
version = "1.0.28-alpha" version = "1.0.29-alpha"
edition = "2021" edition = "2021"
description = "Cardano smart contract language and toolchain" description = "Cardano smart contract language and toolchain"
repository = "https://github.com/aiken-lang/aiken" repository = "https://github.com/aiken-lang/aiken"
@ -24,5 +24,5 @@ tracing = "0.1.37"
url = "2.3.1" url = "2.3.1"
urlencoding = "2.1.2" urlencoding = "2.1.2"
aiken-lang = { path = '../aiken-lang', version = "1.0.28-alpha" } aiken-lang = { path = '../aiken-lang', version = "1.0.29-alpha" }
aiken-project = { path = '../aiken-project', version = "1.0.28-alpha" } aiken-project = { path = '../aiken-project', version = "1.0.29-alpha" }

View File

@ -1,7 +1,7 @@
[package] [package]
name = "aiken-project" name = "aiken-project"
description = "Aiken project utilities" description = "Aiken project utilities"
version = "1.0.28-alpha" version = "1.0.29-alpha"
edition = "2021" edition = "2021"
repository = "https://github.com/aiken-lang/aiken" repository = "https://github.com/aiken-lang/aiken"
homepage = "https://github.com/aiken-lang/aiken" homepage = "https://github.com/aiken-lang/aiken"
@ -41,8 +41,8 @@ toml = "0.7.2"
walkdir.workspace = true walkdir.workspace = true
zip = "0.6.4" zip = "0.6.4"
aiken-lang = { path = "../aiken-lang", version = "1.0.28-alpha" } aiken-lang = { path = "../aiken-lang", version = "1.0.29-alpha" }
uplc = { path = '../uplc', version = "1.0.28-alpha" } uplc = { path = '../uplc', version = "1.0.29-alpha" }
num-bigint = "0.4.4" num-bigint = "0.4.4"
cryptoxide = "0.4.4" cryptoxide = "0.4.4"
vec1 = "1.10.1" vec1 = "1.10.1"

View File

@ -510,6 +510,8 @@ pub enum Warning {
DependencyAlreadyExists { name: PackageName }, DependencyAlreadyExists { name: PackageName },
#[error("Ignoring file with invalid module name at: {path:?}")] #[error("Ignoring file with invalid module name at: {path:?}")]
InvalidModuleName { path: PathBuf }, InvalidModuleName { path: PathBuf },
#[error("aiken.toml demands compiler version {demanded}, but you are using {current}.")]
CompilerVersionMismatch { demanded: String, current: String },
} }
impl ExtraData for Warning { impl ExtraData for Warning {
@ -517,7 +519,8 @@ impl ExtraData for Warning {
match self { match self {
Warning::NoValidators { .. } Warning::NoValidators { .. }
| Warning::DependencyAlreadyExists { .. } | Warning::DependencyAlreadyExists { .. }
| Warning::InvalidModuleName { .. } => None, | Warning::InvalidModuleName { .. }
| Warning::CompilerVersionMismatch { .. } => None,
Warning::Type { warning, .. } => warning.extra_data(), Warning::Type { warning, .. } => warning.extra_data(),
} }
} }
@ -527,7 +530,9 @@ impl GetSource for Warning {
fn path(&self) -> Option<PathBuf> { fn path(&self) -> Option<PathBuf> {
match self { match self {
Warning::InvalidModuleName { path } | Warning::Type { path, .. } => Some(path.clone()), Warning::InvalidModuleName { path } | Warning::Type { path, .. } => Some(path.clone()),
Warning::NoValidators | Warning::DependencyAlreadyExists { .. } => None, Warning::NoValidators
| Warning::DependencyAlreadyExists { .. }
| Warning::CompilerVersionMismatch { .. } => None,
} }
} }
@ -536,7 +541,8 @@ impl GetSource for Warning {
Warning::Type { src, .. } => Some(src.clone()), Warning::Type { src, .. } => Some(src.clone()),
Warning::NoValidators Warning::NoValidators
| Warning::InvalidModuleName { .. } | Warning::InvalidModuleName { .. }
| Warning::DependencyAlreadyExists { .. } => None, | Warning::DependencyAlreadyExists { .. }
| Warning::CompilerVersionMismatch { .. } => None,
} }
} }
} }
@ -551,7 +557,8 @@ impl Diagnostic for Warning {
Warning::Type { named, .. } => Some(named), Warning::Type { named, .. } => Some(named),
Warning::NoValidators Warning::NoValidators
| Warning::InvalidModuleName { .. } | Warning::InvalidModuleName { .. }
| Warning::DependencyAlreadyExists { .. } => None, | Warning::DependencyAlreadyExists { .. }
| Warning::CompilerVersionMismatch { .. } => None,
} }
} }
@ -560,7 +567,8 @@ impl Diagnostic for Warning {
Warning::Type { warning, .. } => warning.labels(), Warning::Type { warning, .. } => warning.labels(),
Warning::InvalidModuleName { .. } Warning::InvalidModuleName { .. }
| Warning::NoValidators | Warning::NoValidators
| Warning::DependencyAlreadyExists { .. } => None, | Warning::DependencyAlreadyExists { .. }
| Warning::CompilerVersionMismatch { .. } => None,
} }
} }
@ -572,6 +580,9 @@ impl Diagnostic for Warning {
))), ))),
Warning::NoValidators => Some(Box::new("aiken::check")), Warning::NoValidators => Some(Box::new("aiken::check")),
Warning::InvalidModuleName { .. } => Some(Box::new("aiken::project::module_name")), Warning::InvalidModuleName { .. } => Some(Box::new("aiken::project::module_name")),
Warning::CompilerVersionMismatch { .. } => {
Some(Box::new("aiken::project::compiler_version_mismatch"))
}
Warning::DependencyAlreadyExists { .. } => { Warning::DependencyAlreadyExists { .. } => {
Some(Box::new("aiken::packages::already_exists")) Some(Box::new("aiken::packages::already_exists"))
} }
@ -582,6 +593,10 @@ impl Diagnostic for Warning {
match self { match self {
Warning::Type { warning, .. } => warning.help(), Warning::Type { warning, .. } => warning.help(),
Warning::NoValidators => None, Warning::NoValidators => None,
Warning::CompilerVersionMismatch { demanded, .. } => Some(Box::new(format!(
"You may want to switch to {}",
demanded.if_supports_color(Stdout, |s| s.purple())
))),
Warning::InvalidModuleName { .. } => Some(Box::new( Warning::InvalidModuleName { .. } => Some(Box::new(
"Module names are lowercase, (ascii) alpha-numeric and may contain dashes or underscores.", "Module names are lowercase, (ascii) alpha-numeric and may contain dashes or underscores.",
)), )),

View File

@ -106,7 +106,18 @@ where
pub fn new(root: PathBuf, event_listener: T) -> Result<Project<T>, Error> { pub fn new(root: PathBuf, event_listener: T) -> Result<Project<T>, Error> {
let config = Config::load(&root)?; let config = Config::load(&root)?;
let project = Project::new_with_config(config, root, event_listener); let demanded_compiler_version = format!("v{}", config.compiler);
let mut project = Project::new_with_config(config, root, event_listener);
let current_compiler_version = config::compiler_version(false);
if demanded_compiler_version != current_compiler_version {
project.warnings.push(Warning::CompilerVersionMismatch {
demanded: demanded_compiler_version,
current: current_compiler_version,
})
}
Ok(project) Ok(project)
} }

View File

@ -1,6 +1,6 @@
use aiken_lang::ast::OnTestFailure; use aiken_lang::ast::OnTestFailure;
pub(crate) use aiken_lang::{ pub(crate) use aiken_lang::{
ast::{Arg, BinOp, DataTypeKey, IfBranch, Span, TypedDataType, TypedTest}, ast::{BinOp, DataTypeKey, IfBranch, Span, TypedArg, TypedDataType, TypedTest},
builtins::bool, builtins::bool,
expr::{TypedExpr, UntypedExpr}, expr::{TypedExpr, UntypedExpr},
format::Formatter, format::Formatter,
@ -124,13 +124,13 @@ impl Test {
let via = parameter.via.clone(); let via = parameter.via.clone();
let type_info = parameter.tipo.clone(); let type_info = parameter.arg.tipo.clone();
let stripped_type_info = convert_opaque_type(&type_info, generator.data_types(), true); let stripped_type_info = convert_opaque_type(&type_info, generator.data_types(), true);
let program = generator.clone().generate_raw( let program = generator.clone().generate_raw(
&test.body, &test.body,
&[Arg { &[TypedArg {
tipo: stripped_type_info.clone(), tipo: stripped_type_info.clone(),
..parameter.clone().into() ..parameter.clone().into()
}], }],

View File

@ -1,7 +1,7 @@
[package] [package]
name = "aiken" name = "aiken"
description = "Cardano smart contract language and toolchain" description = "Cardano smart contract language and toolchain"
version = "1.0.28-alpha" version = "1.0.29-alpha"
edition = "2021" edition = "2021"
repository = "https://github.com/aiken-lang/aiken" repository = "https://github.com/aiken-lang/aiken"
homepage = "https://github.com/aiken-lang/aiken" homepage = "https://github.com/aiken-lang/aiken"
@ -36,10 +36,10 @@ regex = "1.7.1"
serde_json = "1.0.94" serde_json = "1.0.94"
thiserror = "1.0.39" thiserror = "1.0.39"
aiken-lang = { path = "../aiken-lang", version = "1.0.28-alpha" } aiken-lang = { path = "../aiken-lang", version = "1.0.29-alpha" }
aiken-lsp = { path = "../aiken-lsp", version = "1.0.28-alpha" } aiken-lsp = { path = "../aiken-lsp", version = "1.0.29-alpha" }
aiken-project = { path = '../aiken-project', version = "1.0.28-alpha" } aiken-project = { path = '../aiken-project', version = "1.0.29-alpha" }
uplc = { path = '../uplc', version = "1.0.28-alpha" } uplc = { path = '../uplc', version = "1.0.29-alpha" }
clap_complete = "4.3.2" clap_complete = "4.3.2"
inquire = "0.6.2" inquire = "0.6.2"
num-bigint = "0.4.3" num-bigint = "0.4.3"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "uplc" name = "uplc"
description = "Utilities for working with Untyped Plutus Core" description = "Utilities for working with Untyped Plutus Core"
version = "1.0.28-alpha" version = "1.0.29-alpha"
edition = "2021" edition = "2021"
repository = "https://github.com/aiken-lang/aiken" repository = "https://github.com/aiken-lang/aiken"
homepage = "https://github.com/aiken-lang/aiken" homepage = "https://github.com/aiken-lang/aiken"

View File

@ -0,0 +1,28 @@
# This file was generated by Aiken
# You typically do not need to edit this file
[[requirements]]
name = "aiken-lang/stdlib"
version = "main"
source = "github"
[[requirements]]
name = "aiken-lang/fuzz"
version = "main"
source = "github"
[[packages]]
name = "aiken-lang/stdlib"
version = "main"
requirements = []
source = "github"
[[packages]]
name = "aiken-lang/fuzz"
version = "main"
requirements = []
source = "github"
[etags]
"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1717767691, nanos_since_epoch = 206091000 }, "98cf81aa68f9ccf68bc5aba9be06d06cb1db6e8eff60b668ed5e8ddf3588206b"]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1717767690, nanos_since_epoch = 920449000 }, "a746f5b5cd3c2ca5dc19c43bcfc64230c546fafea2ba5f8e340c227b85886078"]

View File

@ -0,0 +1,21 @@
name = "aiken-lang/104"
version = "0.0.0"
compiler = "v1.0.29-alpha"
plutus = "v2"
license = "Apache-2.0"
description = "Aiken contracts for project 'aiken-lang/104'"
[repository]
user = "aiken-lang"
project = "104"
platform = "github"
[[dependencies]]
name = "aiken-lang/stdlib"
version = "main"
source = "github"
[[dependencies]]
name = "aiken-lang/fuzz"
version = "main"
source = "github"

View File

@ -0,0 +1,80 @@
{
"preamble": {
"title": "aiken-lang/104",
"description": "Aiken contracts for project 'aiken-lang/104'",
"version": "0.0.0",
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.29-alpha+257bd23"
},
"license": "Apache-2.0"
},
"validators": [
{
"title": "tests.foo_3",
"redeemer": {
"title": "_data",
"schema": {
"$ref": "#/definitions/Data"
}
},
"parameters": [
{
"title": "th_arg",
"schema": {
"$ref": "#/definitions/tests~1Foo"
}
}
],
"compiledCode": "582401000032323222253330043370e6eb4c018c014dd5001a400429309b2b2b9a5573cae841",
"hash": "047dafbc61fb4a550a28398bde3680c48ff2000cf1022efc883124cd"
}
],
"definitions": {
"Bool": {
"title": "Bool",
"anyOf": [
{
"title": "False",
"dataType": "constructor",
"index": 0,
"fields": []
},
{
"title": "True",
"dataType": "constructor",
"index": 1,
"fields": []
}
]
},
"Data": {
"title": "Data",
"description": "Any Plutus data."
},
"Int": {
"dataType": "integer"
},
"tests/Foo": {
"title": "Foo",
"anyOf": [
{
"title": "Foo",
"dataType": "constructor",
"index": 0,
"fields": [
{
"title": "a0",
"$ref": "#/definitions/Int"
},
{
"title": "a1",
"$ref": "#/definitions/Bool"
}
]
}
]
}
}
}

View File

@ -0,0 +1,45 @@
use aiken/fuzz
type Foo {
a0: Int,
a1: Bool,
}
fn foo_1(Foo { a0, .. }) -> Int {
a0 + 1
}
fn foo_2(Foo { a0, a1 } as foo) -> Int {
if a1 {
a0 + 1
} else {
foo.a0 - 1
}
}
validator(Foo { a0, .. }: Foo) {
fn foo_3(_data, _redeemer) {
a0 == 1
}
}
test example_1() {
foo_1(Foo { a0: 1, a1: False }) == 2
}
test example_2() {
foo_2(Foo { a0: 1, a1: False }) == 0
}
test example_3() {
foo_3(Foo { a0: 1, a1: False }, "", "")
}
test example_4() {
let foo_4 = fn(Foo { a1, .. }) { a1 }
foo_4(Foo { a0: 1, a1: True })
}
test example_5((a, b) via fuzz.both(fuzz.int(), fuzz.int())) {
a + b == b + a
}

52
flake.lock generated vendored
View File

@ -18,31 +18,13 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1709237383, "lastModified": 1718530797,
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=", "narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8", "rev": "b60ebf54c15553b393d144357375ea956f89e9a9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -54,11 +36,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1706487304, "lastModified": 1718428119,
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -77,15 +59,14 @@
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1709519692, "lastModified": 1718763539,
"narHash": "sha256-+ICGcASuUGpx82io6FVkMW7Pv4dvEl1v9A0ZtBKT41A=", "narHash": "sha256-JHqQyO5XppLpMSKBaYlxbmPHMc4DpwuavKIch9W+hv4=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "30c3af18405567115958c577c62548bdc5a251e7", "rev": "69fcfaebbe564d162a85cadeaadd4dec646be4a2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -108,21 +89,6 @@
"repo": "default", "repo": "default",
"type": "github" "type": "github"
} }
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

163
flake.nix
View File

@ -5,88 +5,95 @@
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = { self, rust-overlay, nixpkgs, flake-utils }: outputs = {
flake-utils.lib.eachDefaultSystem (system: self,
let rust-overlay,
pkgs = import nixpkgs { nixpkgs,
inherit system; flake-utils,
overlays = [ rust-overlay.overlays.default ]; }:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
overlays = [rust-overlay.overlays.default];
};
osxDependencies = with pkgs;
lib.optionals stdenv.isDarwin
[
darwin.apple_sdk.frameworks.Security
darwin.apple_sdk.frameworks.CoreServices
];
cargoTomlContents = builtins.readFile ./crates/aiken/Cargo.toml;
version = (builtins.fromTOML cargoTomlContents).package.version;
aiken = pkgs.rustPlatform.buildRustPackage {
inherit version;
name = "aiken";
buildInputs = with pkgs; [openssl] ++ osxDependencies;
nativeBuildInputs = with pkgs; [pkg-config openssl.dev];
src = pkgs.lib.cleanSourceWith {src = self;};
cargoLock.lockFile = ./Cargo.lock;
GIT_COMMIT_HASH_SHORT = self.shortRev or "unknown";
postPatch = ''
substituteInPlace crates/aiken-project/src/config.rs \
--replace "built_info::GIT_COMMIT_HASH_SHORT" \
"Some(\"$GIT_COMMIT_HASH_SHORT\")"
'';
postInstall = ''
mkdir -p $out/share/zsh/site-functions
$out/bin/aiken completion zsh > $out/share/zsh/site-functions/_aiken
mkdir -p $out/share/bash-completion/completions
$out/bin/aiken completion bash > $out/share/bash-completion/completions/aiken
mkdir -p $out/share/fish/vendor_completions.d
$out/bin/aiken completion fish > $out/share/fish/vendor_completions.d/aiken.fish
'';
meta = with pkgs.lib; {
description = "Cardano smart contract language and toolchain";
homepage = "https://github.com/aiken-lang/aiken";
license = licenses.asl20;
mainProgram = "aiken";
}; };
};
osxDependencies = with pkgs; packages = {
lib.optionals stdenv.isDarwin aiken = aiken;
[ darwin.apple_sdk.frameworks.Security default = packages.aiken;
darwin.apple_sdk.frameworks.CoreServices };
];
cargoTomlContents = builtins.readFile ./crates/aiken/Cargo.toml; overlays.default = final: prev: {aiken = packages.aiken;};
version = (builtins.fromTOML cargoTomlContents).package.version;
aiken = pkgs.rustPlatform.buildRustPackage { gitRev =
inherit version; if (builtins.hasAttr "rev" self)
then self.rev
else "dirty";
in {
inherit packages overlays;
name = "aiken"; devShell = pkgs.mkShell {
buildInputs = with pkgs;
[
pkg-config
openssl
cargo-insta
(pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-src" "clippy" "rustfmt" "rust-analyzer"];
})
]
++ osxDependencies;
buildInputs = with pkgs; [ openssl ] ++ osxDependencies; shellHook = ''
nativeBuildInputs = with pkgs; [ pkg-config openssl.dev ]; export GIT_REVISION=${gitRev}
'';
src = pkgs.lib.cleanSourceWith { src = self; }; };
});
cargoLock.lockFile = ./Cargo.lock;
GIT_COMMIT_HASH_SHORT = self.shortRev or "unknown";
postPatch = ''
substituteInPlace crates/aiken-project/src/config.rs \
--replace "built_info::GIT_COMMIT_HASH_SHORT" \
"Some(\"$GIT_COMMIT_HASH_SHORT\")"
'';
postInstall = ''
mkdir -p $out/share/zsh/site-functions
$out/bin/aiken completion zsh > $out/share/zsh/site-functions/_aiken
mkdir -p $out/share/bash-completion/completions
$out/bin/aiken completion bash > $out/share/bash-completion/completions/aiken
mkdir -p $out/share/fish/vendor_completions.d
$out/bin/aiken completion fish > $out/share/fish/vendor_completions.d/aiken.fish
'';
meta = with pkgs.lib; {
description = "Cardano smart contract language and toolchain";
homepage = "https://github.com/aiken-lang/aiken";
license = licenses.asl20;
mainProgram = "aiken";
};
};
packages = {
aiken = aiken;
default = packages.aiken;
};
overlays.default = final: prev: { aiken = packages.aiken; };
gitRev = if (builtins.hasAttr "rev" self) then self.rev else "dirty";
in {
inherit packages overlays;
devShell = pkgs.mkShell {
buildInputs = with pkgs;
[
pkg-config
openssl
cargo-insta
(pkgs.rust-bin.stable.latest.default.override {
extensions = [ "rust-src" "clippy" "rustfmt" ];
})
] ++ osxDependencies;
shellHook = ''
export GIT_REVISION=${gitRev}
'';
};
});
} }