This changes allow to use parenthesis `(` `)` to encapsulate
expressions in addition to braces `{` `}` used to define blocks.
The main use-case is for arithmetic and boolean expressions for which
developers are used to using parenthesis. For example:
```
{ 14 + 42 } * 1337
```
can now be written as:
```
( 14 + 42 ) * 1337
```
This may sound straightforward at first but wasn't necessarily trivial
in Aiken given that (a) everything is an expression, (b) whitespaces
do not generally matter and (c) there's no symbol indicating the end
of a 'statement' (because there's no statement).
Thus, we have to properly disambiguate between:
```
let foo = bar(14 + 42)
```
and
```
let foo = bar
(14 + 42)
```
Before this commit, the latter would be interpreted as a function call
and would lead to a somewhat puzzling error. Now, the newline serves
as a delimiting symbol. The trade-off being that for a function call,
the left parenthesis has to be on the same line as the function name
identifier -- which is a fair trade off. So this is still allowed:
```
let foo = bar(
14 + 42
)
```
As there's very little ambiguity about it.
This fixes#236 and would seemingly allow us to get rid of the leading
`#` in front of tuples.
* add unary op
* parse, typecheck, and code gen it
* express boolean not as unary op as well, previously called negate
Co-authored-by: rvcas <x@rvcas.dev>
## Before
```
× Type-checking
╰─▶ Unknown module field 'ValidityRaneg' in module 'aiken/transaction'
```
## After
```
× Type-checking
╰─▶ Unknown import 'ValidityRaneg' from module 'aiken/transaction'
╭─[../stdlib/validators/tmp.ak:2:1]
2 │ use aiken/interval.{Interval, IntervalBound, IntervalBoundType}
3 │ use aiken/transaction.{ScriptContext, ValidityRaneg}
· ─────────────
4 │
╰────
help: Did you mean to import 'ValidityRange'?
```
## Before
```
× Checking
╰─▶ Unexpected labeled argument
t
╭─[/Users/mati/Devel/OpenSource/time_lock_aiken/validators/time_lock.ak:13:1]
13 │ let now = when context.transaction.validity_range.lower_bound.bound_type is {
14 │ Finite { t } -> t
· ─
15 │ NegativeInfinity -> 0
╰────
```
## After
```
× Type-checking
╰─▶ Unexpected labeled argument 't'
╭─[../stdlib/validators/tmp.ak:10:1]
10 │ let now = when context.transaction.validity_range.lower_bound.bound_type is {
11 │ interval.Finite { t } -> t
· ─
12 │ interval.NegativeInfinity -> 0
╰────
help: The constructor 'Finite' does not have any labeled field. Its fields
must therefore be matched only by position.
Perhaps, try the following:
╰─▶ interval.Finite(t)
```
## Before
```
× Checking
╰─▶ Unknown variable
Finite
╭─[../stdlib/validators/tmp.ak:10:1]
10 │ let now = when context.transaction.validity_range.lower_bound.bound_type is {
11 │ Finite { t } -> t
· ────────────
12 │ NegativeInfinity -> 0
╰────
```
## After
```
× Type-checking
╰─▶ Unknown data-type constructor 'Finite'
╭─[../stdlib/validators/tmp.ak:10:1]
10 │ let now = when context.transaction.validity_range.lower_bound.bound_type is {
11 │ Finite { t } -> t
· ────────────
12 │ NegativeInfinity -> 0
╰────
help: Did you forget to import it?
Data-type constructors are not automatically imported, even if their type is
imported. So, if a module `aiken/pet` defines the following type:
┍━ aiken/pet.ak ━━━━━━━━
│ pub type Pet {
│ Cat
│ Dog
│ }
You must import its constructors explicitly to use them, or prefix them
with the module's name.
┍━ foo.ak ━━━━━━━━
│ use aiken/pet.{Pet, Dog}
│
│ fn foo(pet : Pet) {
│ when pet is {
│ pet.Cat -> // ...
│ Dog -> // ...
│ }
│ }
```