Somehow, these have always been right-associative, when the natural thing to expect is left-associativity. It now matters when trying to crawl down binary tree to display them properly.
Alleviate a bit more the top-level expression parser. Note that we
probably need a bit more disciplined in what we export and at what level
because there doesn't seem to be much logic as for whether a parser is
private, exported to the crate only or to the wide open. I'd be in favor
of exporting everything by default.
Also moved the logic for 'int' and 'string' there though it is trivial. Yet, for bytearray, it tidies things nicely by removing them from the 'utils' module.
Somehow, miette doesn't play well with spans when using chars indices.
So we have to count the number of bytes in strings / chars, so that
spans align accordingly.
Nothing to see here as they all have the same signature. Implementing
arithmetic bin-operators and boolean logic operators will require some
more logic.
This is simply a syntactic sugar which desugarize to a function call with two arguments mapped to the specified binary operator.
Only works for '>' at this stage as a PoC, extending to all binop in the next commit.
Params being unused were being incorrectly reported.
This was because params need to be initialized
at a scope above both the validator functions. This
manifested when using a multi-validator where one of
the params was not used in both validators.
The easy fix was to add a field called
`is_validator_param` to `ArgName`. Then
when infering a function we don't initialize args
that are validator params. We now handle this
in a scope that is created before in the match branch for
validator in the `infer_definition` function. In there
we call `.in_new_scope` and initialize params for usage
detection.
And disable multi-patterns clauses. I was originally just controlling
whether we did disable that from the parser but then I figured we
could actually support multi-patterns clauses quite easily by simply
desugaring a multi-pattern into multiple clauses.
This is only a syntactic sugar, which means that the cost of writing
that on-chain is as expensive as writing the fully expanded form; yet
it seems like a useful shorthand; especially for short clause
expressions.
This commit however disables multi-pattern when clauses, which we do
not support in the code-generation. Instead, one pattern on tuples for
that.
Rules are now as follows:
- If a pipeline contains a newline, then the entire pipeline is formatted over multiple lines.
- If it doesn't, then it's formatted as a single-line UNLESS it cannot fit; in which case, we fallback to multiline again.
This has been bothering me and the more I thought of it the more I
disliked the idea of a warning. The rationale being that in this very
context, there's absolutely no ambiguity. So it is only frustrating
that the parser is even able to make the exact suggestion of what
should be fixed, but still fails.
I can imagine it is going to be very common for people to type:
```
trace "foo"
```
...yet terribly frustrating if they have to remember each time that
this should actually be a string. Because of the `trace`, `todo` and
`error` keywords, we know exactly the surrounding context and what to
expect here. So we can work it nicely.
However, the formatter will re-format it to:
```
trace @"foo"
```
Just for the sake of remaining consistent with the type-system. This
way, we still only manipulate `String` in the AST, but we conveniently
parse a double-quote utf-8 literal when coupled with one of the
specific keywords.
I believe that's the best of both worlds.
The core observation is that **in the context of Aiken** (i.e. on-chain logic)
people do not generally want to use String. Instead, they want
bytearrays.
So, it should be easy to produce bytearrays when needed and it should
be the default. Before this commit, `"foo"` would parse as a `String`.
Now, it parses as a `ByteArray`, whose bytes are the UTF-8 bytes
encoding of "foo".
Now, to make this change really "fool-proof", we now want to:
- [ ] Emit a parse error if we parse a UTF-8 bytearray literal in
place where we would expect a `String`. For example, `trace`,
`error` and `todo` can only be followed by a `String`.
So when we see something like:
```
trace "foo"
```
we know it's a mistake and we can suggest users to use:
```
trace @"foo"
```
instead.
- [ ] Emit a warning if we ever see a bytearray literals UTF-8, which
is either 56 or 64 character long and is a valid hexadecimal string.
For example:
```
let policy_id = "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6"
```
This is _most certainly_ a mistake, as this generates a ByteArray of
56 bytes, which is effectively the hex-encoding of the provided string.
In this scenario, we want to warn the user and inform them they probably meant to use:
```
let policy_id = #"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6"
```
This is not supported by the code generation, so it's a bit of a lie
to have them in the language in the first place. There's arguably not
even any use for constant records, list and tuples to begin with. So
this cleans this up everywhere for the sake of moving forward with the
alpha release.
This now reduces constants to:
- Integer
- ByteArray
- String
Anything else can be declared via a function anyway. We can revisit
this choice later.... or not.
Interestingly enough, chumsky seems to fail when given a 'choice' with
more than 25 elements. That's why this commit groups together some of
the choices as another nested 'choice'.
Todo is fundamentally just a trace and an error. The only reason we kept it as a separate element in the AST is for the formatter to work out whether it should format something back to a todo or something else.
However, this introduces redundancy in the code internally and makes the AIR more complicated than it needs to be. Both todo and errors can actually be represented as trace + errors, and we only need to record their preferred shape when parsing so that we can format them back to what's expected.
We now parse errors as a combination of a trace plus and error term. This is a baby step in order to simplify the code generation down the line and the internal representation of todo / errors.
This however enforces that the argument unifies to a `String`. So this
is more flexible than the previous form, but does fundamentally the
same thing.
Fixes#378.
There's arguably no use case ever for that in the context of on-chain
Plutus. Strings are really just meant to be used for tracing. They
aren't meant to be manipulated as heavily as in classic programming
languages.