simplicityhl 0.4.0

Rust-like language that compiles to Simplicity bytecode.
Documentation
# Match Expression

A match expression conditionally executes code branches.
Which branch is executed depends on the input to the match expression.

```rust
let result: u32 = match f(42) {
    Left(x: u32) => x,
    Right(x: u16) => jet::left_pad_low_16_32(x),
};
```

In the above example, the output of the function call `f(42)` is matched.
`f` returns an output of type `Either<u32, u16>`.
If `f(42)` returns a value that matches the pattern `Left(x: u32)`, then the first match arm is executed.
This arm simply returns the value `x`.
Alternatively, if `f(42)` returns a value that matches the pattern `Right(x: u16)`, then the second match arm is executed.
This arm extends the 16-bit number `x` to a 32-bit number by padding its left with zeroes.
Because of type constraints, the output of `f` must match one of these two patterns.
The whole match expression returns a value of type `u32`, from one of the two arms.

## Explicit typing

In SimplicityHL, the type of variables inside match arms must **always** be written.
This is different from Rust, which has better type inference.

## Pattern matching

There is limited support for pattern matching inside match expressions.

Boolean values can be matched.
The Boolean match expression is the replacement for an "if-then-else" in SimplicityHL.

```rust
let bit_flip: bool = match false {
    false => true,
    true => false,
};
```

Optional values can be matched.
The `Some` arm introduces a variable which must be explicitly typed.

```rust
let unwrap_or_default: u32 = match Some(42) {
    None => 0,
    Some(x: u32) => x,
};
```

Finally, `Either` values can be matched.
Again, variables that are introduced in match arms must be explicitly typed.

```rust
let map_either: u32 = match Left(1337) {
    Left(x: u32) => f(x),
    Right(y: u32) => f(y),
};
```

Match expressions don't support further pattern matching, in contrast to Rust.

```rust
let unwrap_or_default: u32 = match Some((4, 2)) {
    None => 0,
    // this doesn't compile
    Some((y, z): (u16, u16)) => <(u16, u16)>::into((y, z)),
};
```

However, the match arm can contain code that performs the deconstruction.
For example, the tuple `x` of type `(u16, u16)` can be deconstructed into two integers `y` and `z` of type `u16`.

```rust
let unwrap_or_default: u32 = match Some((4, 2)) {
    None => 0,
    Some(x: (u16, u16)) => {
        let (y, z): (u16, u16) = x;
        <(u16, u16)>::into((y, z))
    }
};
```

The match arm can also contain match expressions for further deconstruction.
For example, the sum value `x` of type `Either<u32, u32>` can be matched as either `Left(y: u32)` or `Right(z: u32)`.

```rust
let unwrap_or_default: u32 = match Some(Left(42)) {
    None => 0,
    Some(x: Either<u32, u32>) => match x {
        Left(y: u32) => y,
        Right(z: u32) => z,
    },
};
```