1
1
mirror of https://github.com/anoma/juvix.git synced 2024-11-30 05:42:26 +03:00
Commit Graph

659 Commits

Author SHA1 Message Date
Jan Mas Rovira
44cdd8404b
Fix generation of wildcards in RecordPattern (#2802)
- Closes #2801
2024-06-04 18:28:25 +02:00
Paul Cadman
371f8f2258
Support Anoma stdlib sign-detached API (#2798)
This PR adds support for the Anoma stdlib `sign-detached` API.

```
builtin anoma-sign-detached
axiom anomaSignDetached : {A : Type}
  -- message to sign
  -> A
  -- private key
  -> Nat
 -- signature
  -> Nat;
```

This corresponds to the
[sign_detached](https://hexdocs.pm/enacl/enacl.html#sign_detached-2)
libsodium API.

This is requried to support to new Anoma nullifier format:


d6a61451ae

Previously resource nullifiers were defined using `anomaSign`:

```
nullifier (r : Resource) (secretKey : Nat) : Nat :=
  anomaSign (anomaEncode (nullifierHeader, r)) secretKey;
```

They are now defined using `anomaSignDetached`:

```
nullifier (r : Resource) (secretKey : Nat) : Nat :=
  let encodedResource : Nat := anomaEncode (nullifierHeader, r) in
  anomaEncode (encodedResource , anomaSignDetached encodedResource secretKey);
```

This is so that a logic function can access the nullified resources
directly from the `nullifier` field.

## Evaluator Note

When decoding a public key, private key or signature from an integer
atom to a bytestring it's important to pad the bytestring to the
appropriate number of bytes. For example a private key must be 64 bytes
but the corresponding encoded integer may fit into 63 bytes or fewer
bytes (depending on leading zeros). This PR also fixes this issue by
adding a
[`atomToByteStringLen`](c68c7187b1/src/Juvix/Compiler/Nockma/Encoding/ByteString.hs (L14))
function with also accepts the expected size of the resulting
bytestring.
2024-06-03 19:07:56 +02:00
Paul Cadman
823b37c216
Release 0.6.2 (#2795)
This PR updates:

- [x] Package version
- [x] Smoke test
- [x] Changelog
2024-06-01 11:33:36 +02:00
Jan Mas Rovira
e9afdad82a
Parallel pipeline (#2779)
This pr introduces parallelism in the pipeline to gain performance. I've
included benchmarks at the end.

- Closes #2750.

# Flags:
There are two new global flags:
1. `-N / --threads`. It is used to set the number of capabilities.
According to [GHC
documentation](https://hackage.haskell.org/package/base-4.20.0.0/docs/GHC-Conc.html#v:setNumCapabilities):
_Set the number of Haskell threads that can run truly simultaneously (on
separate physical processors) at any given time_. When compiling in
parallel, we create this many worker threads. The default value is `-N
auto`, which sets `-N` to half the number of logical cores, capped at 8.
2. `--dev-show-thread-ids`. When given, the thread id is printed in the
compilation progress log. E.g.

![image](https://github.com/anoma/juvix/assets/5511599/9359fae2-0be1-43e5-8d74-faa82cba4034)

# Parallel compilation
1. I've added `src/Parallel/ParallelTemplate.hs` which contains all the
concurrency related code. I think it is good to keep this code separated
from the actual compiler code.
2. I've added a progress log (only for the parallel driver) that outputs
a log of the compilation progress, similar to what stack/cabal do.

# Code changes:
1. I've removed the `setup` stage where we were registering
dependencies. Instead, the dependencies are registered when the
`pathResolver` is run for the first time. This way it is safer.
1. Now the `ImportTree` is needed to run the pipeline. Cycles are
detected during the construction of this tree, so I've removed `Reader
ImportParents` from the pipeline.
3. For the package pathresolver, we do not support parallelism yet (we
could add support for it in the future, but the gains will be small).
4. When `-N1`, the pipeline remains unchanged, so performance should be
the same as in the main branch (except there is a small performance
degradation due to adding the `-threaded` flag).
5. I've introduced `PipelineOptions`, which are options that are used to
pass options to the effects in the pipeline.
6. `PathResolver` constraint has been removed from the `upTo*` functions
in the pipeline due to being redundant.
7. I've added a lot of `NFData` instances. They are needed to force the
full evaluation of `Stored.ModuleInfo` in each of the threads.
2. The `Cache` effect uses
[`SharedState`](https://hackage.haskell.org/package/effectful-core-2.3.0.1/docs/Effectful-State-Static-Shared.html)
as opposed to
[`LocalState`](https://hackage.haskell.org/package/effectful-core-2.3.0.1/docs/Effectful-Writer-Static-Local.html).
Perhaps we should provide different versions.
3. I've added a `Cache` handler that accepts a setup function. The setup
is triggered when a miss is detected. It is used to lazily compile the
modules in parallel.

# Tests
1. I've adapted the smoke test suite to ignore the progress log in the
stderr.
5. I've had to adapt `tests/positive/Internal/Lambda.juvix`. Due to
laziness, a crash happening in this file was not being caught. The
problem is that in this file we have a lambda function with different
number of patterns in their clauses, which we currently do not support
(https://github.com/anoma/juvix/issues/1706).
6. I've had to comment out the definition
   ```
   x : Box ((A : Type) → A → A) := box λ {A a := a};
   ```
From the test as it was causing a crash
(https://github.com/anoma/juvix/issues/2247).
# Future Work
1. It should be investigated how much performance we lose by fully
evaluating the `Stored.ModuleInfo`, since some information in it will be
discarded. It may be possible to be more fine-grained when forcing
evaluation.
8. The scanning of imports to build the import tree is sequential. Now,
we build the import tree from the entry point module and only the
modules that are imported from it are in the tree. However, we have
discussed that at some point we should make a distinction between
`juvix` _the compiler_ and `juvix` _the build tool_. When using `juvix`
as a build tool it makes sense to typecheck/compile (to stored core) all
modules in the project. When/if we do this, scanning imports in all
modules in parallel becomes trivial.
9. The implementation of the `ParallelTemplate` uses low level
primitives such as
[forkIO](https://hackage.haskell.org/package/base-4.20.0.0/docs/Control-Concurrent.html#v:forkIO).
At some point it should be refactored to use safer functions from the
[`Effectful.Concurrent.Async`](https://hackage.haskell.org/package/effectful-2.3.0.0/docs/Effectful-Concurrent-Async.html)
module.
10. The number of cores and worker threads that we spawn is determined
by the command line. Ideally, we could use to import tree to compute an
upper bound to the ideal number of cores to use.
11. We could add an animation that displays which modules are being
compiled in parallel and which have finished being compiled.

# Benchmarks

On some benchmarks, I include the GHC runtime option
[`-A`](https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html#rts-flag--A%20%E2%9F%A8size%E2%9F%A9),
which sometimes makes a good impact on performance. Thanks to
@paulcadman for pointing this out. I've figured a good combination of
`-N` and `-A` through trial and error (but this oviously depends on the
cpu and juvix projects).

## Typecheck the standard library
   
### Clean run (88% faster than main):
```
 hyperfine --warmup 1 --prepare 'juvix clean' 'juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432'  'juvix -N 4 typecheck Stdlib/Prelude.juvix' 'juvix-main typecheck Stdlib/Prelude.juvix'
Benchmark 1: juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432
  Time (mean ± σ):     444.1 ms ±   6.5 ms    [User: 1018.0 ms, System: 77.7 ms]
  Range (min … max):   432.6 ms … 455.9 ms    10 runs

Benchmark 2: juvix -N 4 typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):     628.3 ms ±  23.9 ms    [User: 1227.6 ms, System: 69.5 ms]
  Range (min … max):   584.7 ms … 670.6 ms    10 runs

Benchmark 3: juvix-main typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):     835.9 ms ±  12.3 ms    [User: 788.5 ms, System: 31.9 ms]
  Range (min … max):   816.0 ms … 853.6 ms    10 runs

Summary
  juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432 ran
    1.41 ± 0.06 times faster than juvix -N 4 typecheck Stdlib/Prelude.juvix
    1.88 ± 0.04 times faster than juvix-main typecheck Stdlib/Prelude.juvix
```
   
### Cached run (43% faster than main):
```
hyperfine --warmup 1 'juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432'  'juvix -N 4 typecheck Stdlib/Prelude.juvix' 'juvix-main typecheck Stdlib/Prelude.juvix'
Benchmark 1: juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432
  Time (mean ± σ):     241.3 ms ±   7.3 ms    [User: 538.6 ms, System: 101.3 ms]
  Range (min … max):   231.5 ms … 251.3 ms    11 runs

Benchmark 2: juvix -N 4 typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):     235.1 ms ±  12.0 ms    [User: 405.3 ms, System: 87.7 ms]
  Range (min … max):   216.1 ms … 253.1 ms    12 runs

Benchmark 3: juvix-main typecheck Stdlib/Prelude.juvix
  Time (mean ± σ):     336.7 ms ±  13.3 ms    [User: 269.5 ms, System: 67.1 ms]
  Range (min … max):   316.9 ms … 351.8 ms    10 runs

Summary
  juvix -N 4 typecheck Stdlib/Prelude.juvix ran
    1.03 ± 0.06 times faster than juvix -N 4 typecheck Stdlib/Prelude.juvix +RTS -A33554432
    1.43 ± 0.09 times faster than juvix-main typecheck Stdlib/Prelude.juvix
```
## Typecheck the test suite of the containers library
At the moment this is the biggest juvix project that we have.

### Clean run (105% faster than main)
```
hyperfine --warmup 1 --prepare 'juvix clean' 'juvix -N 6 typecheck Main.juvix +RTS -A67108864' 'juvix -N 4 typecheck Main.juvix' 'juvix-main typecheck Main.juvix'
Benchmark 1: juvix -N 6 typecheck Main.juvix +RTS -A67108864
  Time (mean ± σ):      1.006 s ±  0.011 s    [User: 2.171 s, System: 0.162 s]
  Range (min … max):    0.991 s …  1.023 s    10 runs

Benchmark 2: juvix -N 4 typecheck Main.juvix
  Time (mean ± σ):      1.584 s ±  0.046 s    [User: 2.934 s, System: 0.149 s]
  Range (min … max):    1.535 s …  1.660 s    10 runs

Benchmark 3: juvix-main typecheck Main.juvix
  Time (mean ± σ):      2.066 s ±  0.010 s    [User: 1.939 s, System: 0.089 s]
  Range (min … max):    2.048 s …  2.077 s    10 runs

Summary
  juvix -N 6 typecheck Main.juvix +RTS -A67108864 ran
    1.57 ± 0.05 times faster than juvix -N 4 typecheck Main.juvix
    2.05 ± 0.03 times faster than juvix-main typecheck Main.juvix
```

### Cached run (54% faster than main)
```
hyperfine --warmup 1 'juvix -N 6 typecheck Main.juvix +RTS -A33554432'  'juvix -N 4 typecheck Main.juvix' 'juvix-main typecheck Main.juvix'
Benchmark 1: juvix -N 6 typecheck Main.juvix +RTS -A33554432
  Time (mean ± σ):     551.8 ms ±  13.2 ms    [User: 1419.8 ms, System: 199.4 ms]
  Range (min … max):   535.2 ms … 570.6 ms    10 runs

Benchmark 2: juvix -N 4 typecheck Main.juvix
  Time (mean ± σ):     636.7 ms ±  17.3 ms    [User: 1006.3 ms, System: 196.3 ms]
  Range (min … max):   601.6 ms … 655.3 ms    10 runs

Benchmark 3: juvix-main typecheck Main.juvix
  Time (mean ± σ):     847.2 ms ±  58.9 ms    [User: 710.1 ms, System: 126.5 ms]
  Range (min … max):   731.1 ms … 890.0 ms    10 runs

Summary
  juvix -N 6 typecheck Main.juvix +RTS -A33554432 ran
    1.15 ± 0.04 times faster than juvix -N 4 typecheck Main.juvix
    1.54 ± 0.11 times faster than juvix-main typecheck Main.juvix
```
2024-05-31 12:41:30 +01:00
Łukasz Czajka
55598e0f95
Rust backend (#2787)
* Implements code generation through Rust.
* CLI: adds two `dev` compilation targets: 
  1. `rust` for generating Rust code
  2. `native-rust` for generating a native executable via Rust
* Adds end-to-end tests for compilation from Juvix to native executable
via Rust.
* A target for RISC0 needs to be added in a separate PR building on this
one.
2024-05-29 13:34:04 +02:00
Paul Cadman
9faa88d4da
Add support for Strings in the Anoma backend (#2789)
This PR adds support for the `String` type, String literals and string
concatenation to the Nockma backend. Support for the builtins `show` and
`intToString` is not supported.

### Example

test079.juvix
```
module test079;

import Stdlib.Prelude open;

main (s : String) : String :=
  s ++str " " ++str " héllo" ++str " " ++str "world ";
```

args.nockma
```
[quote "Juvix!"]
```

```
$ juvix compile anoma test079.juvix
$ juvix dev nockma run test079.pretty.nockma --args args.nockma
"Juvix!  héllo world "
```

### String representation

A String is a sequence of UTF-8 encoded bytes. We interpret these bytes
as a sequence of bits to represent the string as an integer atom in
nockma.

For example:

The string `"a"` is UTF-8 encoded as `97` which is `0b1100001` in bits.

The string `"ab"` is UTF-8 encoded at the pair of bytes: `97 98` which
is `0b1100001 0b1100010`.

When we combine the bytes into a single sequence of bits we must take
care to pad each binary representation with zeros to each byte boundary.

So the binary representation of `"ab"` as an atom is `0b110000101100010`
or `24930` as an integer atom.

### String concatenation

We use the
[cat](ea25f88cea/hoon/anoma.hoon (L215))
function in the Anoma stdlib to concatenate the bytes representing two
strings.

We need to use the block parameter `3` in the Anoma call because we want
to treat the atoms representing the strings as sequences of bytes (= 2^3
bits).

To find the relevant Nock code to call `cat` with block parameter `3` we
use the urbit dojo as follows:

```
 =>  anoma  !=(~(cat block 3))
[8 [9 10 0 7] 9 4 10 [6 7 [0 3] 1 3] 0 2]
```

### Stdlib intercept in Evaluator

The evaluator has support for strings using `AtomHint`s, so strings can
be printed and traced. The stdlib `cat` call is also intercepted because
evaluating the unjetted hoon version is slow.

### String support in pretty nockma

In a pretty nockma file or `nock` quasi-quote you can write double
quoted string literals, e.g "abc". These are automatically translated to
UTF-8 integer atoms as in the previous section.
2024-05-28 17:20:19 +01:00
Paul Cadman
e30905ae95
Support Anoma stdlib APIs sign and verify (#2788)
This PR adds support for the Anoma stdlib `sign` and `verify` APIs.

```
builtin anoma-sign
axiom anomaSign : {A : Type}
  -- message to sign
  -> A
  -- secret key
  -> Nat
  -- signed message
  -> Nat;

builtin anoma-verify
axiom anomaVerify : {A : Type}
  -- signed message to verify 
  -> Nat 
  -- public key
  -> Nat 
  -- message with signature removed
  -> A;
```

These correspond to the
[`sign`](https://hexdocs.pm/enacl/enacl.html#sign-2) and
[`sign_open`](https://hexdocs.pm/enacl/enacl.html#sign_open-2) APIs from
libsodium respectively.

If signature verification fails in `anomaVerify`, the Anoma program
exits. We copy this behaviour in the evaluator by throwing an error in
this case.

## Notes

The Haskell Ed25519 library does not support `sign_open`. Its
verification function returns Bool, i.e it checks that the signature is
valid. The signed message is simply the concatenation of the signature
(64 bytes) and the original message so I added a function to remove the
signature from a signed message.
2024-05-28 09:02:03 +01:00
Paul Cadman
830bf04275
Support Anoma stdlib API verifyDetached (#2785)
This PR adds support for`anomaVerifyDetached` stdlib API via a Juvix
builtin.

It has signature:

```
builtin anoma-verify-detached
axiom anomaVerifyDetached : {A : Type}
   --- signature
  -> Nat 
   --- message
  -> A
   --- public key
  -> Nat
 -> Bool;
```

The [ed25519](https://hackage.haskell.org/package/ed25519) library is
used in the evaluator becuase Anoma uses ed25519 signatures
(https://hexdocs.pm/enacl/enacl.html).

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-05-23 13:40:05 +01:00
Łukasz Czajka
161a34c36b
Optional braces in case syntax (#2778)
* Closes #2769 
* Removes old case syntax
* Pretty printing doesn't print braces in `case` if the `case` is a
"top" expression in a definition.
2024-05-22 18:14:03 +01:00
Paul Cadman
60bffcfeb8
refactor: Add Anoma Node in Tree language (#2784)
Similarly to how the Cairo operations are handled we add a separate Tree
language Node for Anoma operations instead of handling them as an Unop
Node.

This is necessary because we need to add support for new Anoma
operations that are not unary.

This PR also adds support for `anoma-encode` and `anoma-decode`
functions in `jvt` tree source files which was missed in the previous
PRs.
2024-05-17 09:14:05 +01:00
Paul Cadman
52f8afdb2b
Add support for anoma-decode builtin (#2775)
This PR adds support for the `anoma-decode` builtin

```
builtin anoma-decode
axiom anomaDecode : {A : Type} -> Nat -> A
```

Adds:
* An implementation of the `cue` function in Haskell
* Unit tests for `cue`
* A benchmark for `cue` applied to the Anoma / nockma stdlib

Benchmark results:

```
      cue (jam stdlib): OK
        36.0 ms ± 2.0 ms
```

Closes:
*  https://github.com/anoma/juvix/issues/2764
2024-05-15 18:30:17 +01:00
Łukasz Czajka
325d43f172
Support type synonyms in instance types (#2772)
* Closes #2358
2024-05-15 14:29:44 +02:00
Łukasz Czajka
d59d02ccb7
Bugfix: modules associated with inductive types should be declared after their inductive types (#2768)
* Closes #2763. 
* Fixes a bug in the scoper, likely introduced in
https://github.com/anoma/juvix/pull/2468 by making later declarations
depend on earlier ones. The problem was that the inductive modules were
always added at the beginning of a section, which resulted in an
incorrect definition dependency graph (an inductive type depended on its
associated projections).
* Now inductive modules are added just after a group of inductive
definitions, before the next function definition. This implies that
inductive type definitions which depend on each other cannot be
separated by function definitions. Existing Juvix code needs to be
adjusted.
* The behaviour is now equivalent to "manually" inserting module
declarations with projections after each group of inductive definitions.
2024-05-14 19:32:22 +02:00
Paul Cadman
1ab94f5537
Add support for anoma-encode builtin (#2766)
This PR adds support for the `anoma-encode` builtin:

```
builtin anoma-encode
axiom anomaEncode : {A : Type} -> A -> Nat
```

In the backend this is compiled to a call to the Anoma / nockma stdlib
`jam` function.

This PR also contains:
* An implementation of the `jam` function in Haskell. This is used in
the Nockma evaluator.
* Unit tests for `jam`
* A benchmark for `jam` applied to the Anoma / nockma stdlib.

Benchmark results:

```
$ juvixbench -p 'Jam'
All
  Nockma
    Jam
      jam stdlib: OK
        109  ms ± 6.2 ms
```
2024-05-14 17:45:49 +01:00
Jan Mas Rovira
7c59e2aa10
Import tree (#2751)
- Contributes to #2750 

# New commands:
1. `dev import-tree scan FILE`. Scans a single file and lists all the
imports in it.
2. `dev import-tree print`. Scans all files in the package and its
dependencies. Builds an import dependency tree and prints it to stdin.
If the `--stats` flag is given, it reports the number of scanned
modules, the number of unique imports, and the length of the longest
import chain.

Example: this is the truncated output of `juvix dev import-tree print
--stats` in the `juvix-stdlib` directory.
```
[...]
Stdlib/Trait/Partial.juvix imports Stdlib/Data/String/Base.juvix
Stdlib/Trait/Partial.juvix imports Stdlib/Debug/Fail.juvix
Stdlib/Trait/Show.juvix imports Stdlib/Data/String/Base.juvix
index.juvix imports Stdlib/Cairo/Poseidon.juvix
index.juvix imports Stdlib/Data/Int/Ord.juvix
index.juvix imports Stdlib/Data/Nat/Ord.juvix
index.juvix imports Stdlib/Data/String/Ord.juvix
index.juvix imports Stdlib/Prelude.juvix

Import Tree Statistics:
=======================
• Total number of modules: 56
• Total number of edges: 193
• Height (longest chain of imports): 15
```

Bot commands support the `--scan-strategy` flag, which determines which
parser we use to scan the imports. The possible values are:
1. `flatparse`. It uses the low-level
[FlatParse](https://hackage.haskell.org/package/flatparse-0.5.1.0/docs/FlatParse-Basic.html)
parsing library. This parser is made specifically to only parse imports
and ignores the rest. So we expect this to have a much better
performance. It does not have error messages.
2. `megaparsec`. It uses the normal juvix parser and we simply collect
the imports from it.
4. `flatparse-megaparsec` (default). It uses the flatparse backend and
fallbacks to megaparsec if it fails.

# Internal changes
## Megaparsec Parser (`Concrete.FromSource`)
In order to be able to run the parser during the scanning phase, I've
adjusted some of the effects used in the parser:
1. I've removed the `NameIdGen` and `Files` constraints, which were
unused.
2. I've removed `Reader EntryPoint`. It was used to get the `ModuleId`.
Now the `ModuleId` is generated during scoping.
3. I've replaced `PathResolver` by the `TopModuleNameChecker` effect.
This new effect, as the name suggests, only checks the name of the
module (same rules as we had in the `PathResolver` before). It is also
possible to ignore the effect, which is needed if we want to use this
parser without an entrypoint.

## `PathResolver` effet refactor
1. The `WithPath` command has been removed.
2. New command `ResolvePath :: ImportScan -> PathResolver m
(PackageInfo, FileExt)`. Useful for resolving imports during scanning
phase.
3. New command `WithResolverRoot :: Path Abs Dir -> m a -> PathResolver
m a`. Useful for switching package context.
4. New command `GetPackageInfos :: PathResolver m (HashMap (Path Abs
Dir) PackageInfo)` , which returns a table with all packages. Useful to
scan all dependencies.

The `Package.PathResolver` has been refactored to be more like to normal
`PathResolver`. We've discussed with @paulcadman the possibility to try
to unify both implementations in the near future.

## Misc
1. `Package.juvix` no longer ends up in
`PackageInfo.packageRelativeFiles`.
1. I've introduced string definitions for `--`, `{-` and `-}`.
2. I've fixed a bug were `.juvix.md` was detected as an invalid
extension.
3. I've added `LazyHashMap` to the prelude. I've also added `ordSet` to
create ordered Sets, `ordMap` for ordered maps, etc.

# Benchmarks
I've profiled `juvix dev import-tree --scan-strategy [megaparsec |
flatparse] --stats` with optimization enabled.
In the images below we see that in the megaparsec case, the scanning
takes 54.8% of the total time, whereas in the flatparse case it only
takes 9.6% of the total time.

- **Megaparsec**

![image](https://github.com/anoma/juvix/assets/5511599/05ec42cf-d79d-4bbf-b462-c0e48593fe51)

- **Flatparse**

![image](https://github.com/anoma/juvix/assets/5511599/1d7b363c-a915-463c-8dc4-613ab4b7d473)

## Hyperfine
```
hyperfine --warmup 1 'juvix dev import-tree print --scan-strategy flatparse --stats' 'juvix dev import-tree print --scan-strategy megaparsec --stats' --min-runs 20
Benchmark 1: juvix dev import-tree print --scan-strategy flatparse --stats
  Time (mean ± σ):      82.0 ms ±   4.5 ms    [User: 64.8 ms, System: 17.3 ms]
  Range (min … max):    77.0 ms … 102.4 ms    37 runs

Benchmark 2: juvix dev import-tree print --scan-strategy megaparsec --stats
  Time (mean ± σ):     174.1 ms ±   2.7 ms    [User: 157.5 ms, System: 16.8 ms]
  Range (min … max):   169.7 ms … 181.5 ms    20 runs

Summary
  juvix dev import-tree print --scan-strategy flatparse --stats ran
    2.12 ± 0.12 times faster than juvix dev import-tree print --scan-strategy megaparsec --stats
```

In order to compare (almost) only the parsing, I've forced the scanning
of each file to be performed 50 times (so that the cost of other parts
get swallowed). Here are the results:
```
hyperfine --warmup 1 'juvix dev import-tree print --scan-strategy flatparse --stats' 'juvix dev import-tree print --scan-strategy megaparsec --stats' --min-runs 10
Benchmark 1: juvix dev import-tree print --scan-strategy flatparse --stats
  Time (mean ± σ):     189.5 ms ±   3.6 ms    [User: 161.7 ms, System: 27.6 ms]
  Range (min … max):   185.1 ms … 197.1 ms    15 runs

Benchmark 2: juvix dev import-tree print --scan-strategy megaparsec --stats
  Time (mean ± σ):      5.113 s ±  0.023 s    [User: 5.084 s, System: 0.035 s]
  Range (min … max):    5.085 s …  5.148 s    10 runs

Summary
  juvix dev import-tree print --scan-strategy flatparse --stats ran
   26.99 ± 0.52 times faster than juvix dev import-tree print --scan-strategy megaparsec --stats
```
2024-05-14 10:53:33 +02:00
Łukasz Czajka
851afbaa99
Multiway if syntax (#2770)
* Closes #2736
2024-05-08 16:18:34 +02:00
Paul Cadman
640d96e0db
Deduplicate project remote dependencies (#2761)
## Goal

The goal of this PR is to deduplicate all dependencies in a Juvix
project.

Two dependencies are __identical__ when:

* For path dependencies, their paths are equal
* For git dependencies, their URL and their resolved revision (i.e the
git revision hash after resolving a tag) are equal

For example in the following dependency tree, where each of the named
dependencies represent identical git dependencies.

```
MyPkg
|
|-- Dep1-hash1
|   |
|   |-- Dep2-hash2
|   |   |
|   |   `-- Stdlib-hash3
|   |
|   `-- Stdlib-hash3
|
|-- Dep2-hash2
|   |
|   `-- Stdlib-hash3
|
`-- Stdlib-hash3
```

The project `MyPkg` should just contain the following dependencies:
`Dep1-hash1, Dep2-hash2, Stdlib-hash3`.

## Design

### Storage of transitive dependencies

Currently the transitive dependencies of a project are fetched/stored in
`.juvix-build` directories of the corresponding dependencies. After this
PR all dependencies, including transitive ones are stored in the
`.juvix-build` directory of the root project.

Again, assuming that all the transitive dependencies have the same git
hash, in the file system we label the dependencies with their git hash.

```
MyPkg
|
`- .juvix-build
          |- Dep1-hash1
          |- Dep2-hash2
          `- Stdlib-hash3
```

Say we have two versions of `Dep2` in the transitive dependency graph:

```
MyPkg
|
|-- Dep1-hash1
|   |
|   |-- Dep2-hash2
|   |   |
|   |   `-- Stdlib-hash3
|   |
|   `-- Stdlib-hash3
|
|-- Dep2-hash4
|   |
|   `-- Stdlib-hash3
|
`-- Stdlib-hash3
```

we would have two copies of `Dep2` in the `.juvix-build` directory with
different hashes:

```
MyPkg
|
`- .juvix-build
          |- Dep1-hash1
          |- Dep2-hash2
          |- Dep2-hash4
          `- Stdlib-hash3
```

### Storage of git clones

As a consequence of this design we cannot store the git clones for each
dependency in the `.juvix-build` directory as we do now.

We now store the git clones in a global directory
`~/.config/juvix/0.6.1/git-cache`.

When a dependency at a particular revision is required, the global git
clone is fetched/checked out at the required revision and copied into
the `.juvix-build` directory of the relevant project.

### Naming of git clones

The requirement for the naming of the global git clones is that they can
be identified by URL.

In this PR the name of a clone is formed by taking the SHA256 hash of
the dependency git URL. This is to avoid issues with file-system safe
escaping of characters.

### Naming of dependency directories

The requirement for the naming of the dependency directories is that
they can be identified by URL.
 / revision in accordance with our definition of identical dependencies.

In this PR the name of a clone is formed by taking the SHA256 hash of
the concatenation of the dependency git URL and git revision. This is to
avoid issues with file-system safe escaping of characters.

The downside of this approach is that it's hard to see which directories
correspond to which dependencies when navigating the filesystem.
However, navigating using the Juvix tooling by using go-to-definition
etc. will continue to work as before.

## Benchmarks

I tested using [`juvix-containers` test
`Main.juvix`](ebe8d2a873/test/Main.juvix).

The following benchmarks show timings excluding the initial clone of
dependencies (which happens in the warmup run).

Before:
```
$ juvix clean && juvix clean -g
$ hyperfine -w 1 'juvix compile native Main.juvix'
Benchmark 1: juvix compile native Main.juvix
  Time (mean ± σ):      5.598 s ±  0.410 s    [User: 5.020 s, System: 0.586 s]
  Range (min … max):    5.106 s …  6.382 s    10 runs
```

After:
```
$ juvix clean && juvix clean -g
$ hyperfine -w 1 'juvix compile native Main.juvix'
Benchmark 1: juvix compile native Main.juvix
  Time (mean ± σ):      4.418 s ±  0.241 s    [User: 4.083 s, System: 0.343 s]
  Range (min … max):    4.237 s …  4.927 s    10 runs
```

The time saved is due to the fact that before the project depends on 2
copies of the stdlib and after the project depends on 1 copy of the
stdlib.

Time is also saved in the initial run because the stdlib is only cloned
once instead of twice. The cached stdlib clone is also shared between
all project which will improve the performance of all projects that use
the stdlib.

Closes
* https://github.com/anoma/juvix/issues/2760
2024-05-03 19:28:25 +01:00
Łukasz Czajka
4d229eb9f9
Fully respect _evalOptionsNoFailure in the Core evaluator (#2756)
* Closes #2742
2024-04-30 14:09:01 +01:00
Jan Mas Rovira
8497c29982
Add integer literals with bases (#2746)
- Closes #2735 

Allow integer literals to be expressed in different bases:
1. binary, with prefix `0b`.
2. octal, with prefix `0o`.
3. decimal, with no prefix.
4. hexadecimal, with prefix `0x`. Both capital and lower case letters
are parsed. They are always printed as lower case letters.

This applies to all languages that use integer literals, but only in the
concrete language the base will be preserved when pretty printing.
2024-04-22 17:07:32 +02:00
Łukasz Czajka
8b8f323bf1
Cairo Elliptic Curve builtin (#2731)
* Closes #2720 
* Depends on https://github.com/anoma/juvix-cairo-vm/pull/3. For proper
functioning, the latest version of `juvix-cairo-vm` needs to be
installed.
2024-04-22 14:24:09 +02:00
Paul Cadman
52a3eed162
Support extract-module-statements attribute in juvix code blocks (#2734)
This PR adds support for the `extract-module-statements` attribute for
Juvix code blocks:

So if you write something like the following block in a Juvix markdown
file:

````
```juvix extract-module-statements
module Foo;
   type T := t;
end;
```
````

The statement `type T := t;` from the body of the module is rendered in
the output. The `module Foo;` , and `end;` lines are not rendered in the
output.

A block with the `extract-module-statements` must contain a single local
module statement and nothing else. An error is reported if this is not
the case.

The `extract-module-statements` attribute also takes an optional
argument. It sets the number of statements from the module body to drop
from the output.

In the following example, the output will contain the single line `a : T
:= t;`.

````
```juvix extract-module-statements 1
module Foo;
   type T := t;
   a : T  := t;
end;
```
````

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-04-18 17:01:59 +01:00
Łukasz Czajka
75b5228258
Cairo Poseidon hash builtin support (#2723)
* Closes #2719
2024-04-18 14:11:57 +02:00
Jan Mas Rovira
65176a333d
refactor --target into subcommands for dev tree compile and other improvements (#2713)
- refactor `--target` into subcommands for `dev tree compile`.
- prepend `App` to all `CompileTarget` constructors to avoid name
clashes with `Target`.
- parameterize compile options type with the input kind. The input kind
indicates the expected file extension of the input file. If the input
file is a .juvix file, then it is optional, otherwise it is mandatory.
- Add `AppError MegaparsecError` instance and simplify some related
code.
2024-04-16 17:32:44 +02:00
Jan Mas Rovira
2d36a65324
Make compile targets a subcommand instead of a flag (#2700)
# Changes
The main goal of this pr is to remove the `--target` flag for `juvix
compile` and use subcommands instead. The targets that are relevant to
normal users are found in `juvix compile --help`. Targets that are
relevant only to developers are found in `juvix dev compile --help`.

Below I list some of the changes in more detail.
## Compile targets for user-facing languages
- `juvix compile native`
- `juvix compile wasi`. I wasn't sure how to call this: `wasm`,
`wasm32-wasi`, etc. In the end I thought `wasi` was short and accurate,
but we can change it.
- `juvix compile vampir`
- `juvix compile anoma`
- `juvix compile cairo`
## *New* compile targets for internal languages
See `juvix dev compile --help`.

1. `dev compile core` has the same behaviour as `dev core
from-concrete`. The `dev core from-concrete` is redundant at the moment.
2. `dev compile tree` compiles to Tree and prints the InfoTable to the
output file wihout any additional checks.
3. `dev compile reg` compiles to Reg and prints the InfoTable to the
output file wihout any additional checks.
4. `dev compile asm` compiles to Asm and prints the InfoTable to the
output file wihout any additional checks.
5. 4. `dev compile casm` compiles to Asm and prints the Result to the
output file wihout any additional checks. TODO: should the Result be
printed or something else? At the moment the Result lacks a pretty
instance.
6. 
## Optional input file
1. The input file for commands that expect a .juvix file as input is now
optional. If the argument is ommited, he main file given in the
package.yaml will be used. This applies to the following commands:
   1. `juvix compile [native|wasi|geb|vampir|anoma|cairo]`
   8.  `juvix dev compile [core|reg|tree|casm|asm]`
   1. `juvix html`
   3. `juvix markdown`.
   4. `juvix dev internal [typecheck|pretty]`.
   5. `juvix dev [parse|scope]`
   7. `juvix compile [native|wasi|geb|vampir|anoma|cairo]`
   9. note that `juvix format` has not changed its behaviour.

## Refactor some C-like compiler flags
Both `juvix compile native` and `juvix compile wasi` support `--only-c`
(`-C`), `--only-preprocess` (`-E`), `--only-assemble` (`-S`). I propose
to deviate from the `gcc` style and instead use a flag with a single
argument:
- `--cstage [source|preprocess|assembly|exec(default)]`. I'm open to
suggestions. For now, I've kept the legacy flags but marked them as
deprecated in the help message.

## Remove code duplication
I've tried to reduce code duplication. This is sometimes in tension with
code readability so I've tried to find a good balance. I've tried to
make it so we don't have to jump to many different files to understand
what a single command is doing. I'm sure there is still room for
improvement.

## Other refactors
I've implemented other small refactors that I considered improved the
quality of the code.

## TODO/Future work
We should refactor commands (under `compile dev`) which still use
`module Commands.Extra.Compile` and remove it.
2024-04-09 13:29:07 +02:00
Łukasz Czajka
651875ec89
Support Cairo VM input hints (#2709)
* Closes #2687 
* Adds hint support in CASM. The supported hints are `Input(var)` and
`Alloc(size)`. These are the hints currently implemented in
[juvix-cairo-vm](https://github.com/anoma/juvix-cairo-vm).
* Adds the `--program_input` option to the `juvix dev casm run` command.
* Enables private inputs via `main` arguments. In generated CASM/Cairo
code, the arguments to `main` are fetched using the `Input` hint.
* Modifies the CI to use
[juvix-cairo-vm](https://github.com/anoma/juvix-cairo-vm)
2024-04-09 11:43:57 +02:00
Łukasz Czajka
279db701c1
Cairo field compatibility (#2712)
This PR implements changes to make the `eval` command and internal
development commands fully Cairo-compatible.
* Change the default field size to Cairo field size
* Change the printing of "negative" field elements to be compatible with
the Cairo VM
* Quote function names in the Reg to CASM translation
2024-04-09 10:15:47 +02:00
Łukasz Czajka
ee2f8aefbc
Fix memory access order in the JuvixReg to CASM translation. (#2697)
Cairo VM imposes restrictions on memory access order stricter than
described in the documentation, which necessitates changing the
compilation concept for local variables.

Summary
-------------

To ensure that memory is accessed sequentially at all times, we divide
instructions into basic blocks. Within each basic block, the `ap` offset
(i.e. how much `ap` increased since the beginning of the block) is known
at each instruction, which allows to statically associate `fp` offsets
to local variables while still generating only sequential assignments to
`[ap]` with increasing `ap`. When the `ap` offset can no longer be
statically determined for new local variables (e.g. due to an
intervening recursive call), we switch to the next basic block by
calling it with the `call` instruction. The arguments of the basic block
call are the variables live at the beginning of the called block. Note
that the `fp` offsets of "old" variables are still statically determined
even after the current `ap` offset becomes unknown -- the arbitrary
increase of `ap` does not influence the previous variable associations.
Hence, we can transfer the needed local variables to the next basic
block.

Example
-----------

The JuvixReg function
```
function f(integer) : integer {
  tmp[0] = add arg[0] 1;
  tmp[1] = call g(tmp[0]);
  tmp[2] = add tmp[1] arg[0];
  tmp[3] = mul tmp[2] 2;
  tmp[4] = call g(tmp[2]);
  tmp[5] = add tmp[4] tmp[3];
  ret tmp[5];
}
```
is compiled to
```
f:
  -- code for basic block 1
  [ap] = [fp - 3] + 1; ap++
  -- now [fp] is tmp[0], because fp = ap at function start (ap offset is zero) 
  -- transfer call argument (in this case, could be optimized away)
  [ap] = [fp]; ap++
  call g
  -- now [ap - 1] contains the result tmp[1] (it is already a call argument now)
  -- we additionally transfer arg[0] which is live in the next block
  [ap] = [fp - 3]; ap++
  call rel 3
  ret
  nop

  -- code for basic block 2
  -- the above "call rel" jumps here
  -- [fp - 4] is tmp[1] 
  -- [fp - 3] is arg[0]
  [ap] = [fp - 4] + [fp - 3]; ap++
  -- now [fp] is tmp[2]
  [ap] = [fp] * 2; ap++
  -- now [fp + 1] is tmp[3]
  [ap] = [fp]; ap++
  call g
  -- now [ap - 1] is tmp[4]
  [ap] = [fp + 1]; ap++
  call rel 3
  ret
  nop

  -- code for basic block 3
  -- [fp - 4] is tmp[4]
  -- [fp - 3] is tmp[3]
  [ap] = [fp - 4] + [fp - 3]; ap++
  -- now [fp] is tmp[5]
  -- the next assignment could be optimized away in this case
  [ap] = [fp]; ap++
  ret  
```
There are three basic blocks separated by the `call` instructions. In
each basic block, we know statically the `ap` offset at each instruction
(i.e. how much `ap` increased since the beginning of the block). We can
therefore associate the temporary variables with `[fp + k]` for
appropriate `k`. At basic block boundaries we transfer live temporary
variables as arguments for the call to the next basic block.

Checklist
------------
- [x] Divide JuvixReg instructions into [basic
blocks](https://en.wikipedia.org/wiki/Basic_block).
- [x] Implement liveness analysis for each basic block.
- [x] Translate transitions between basic blocks into CASM relative
calls with local live variable transfer.
- [x] Tests for the translation from JuvixReg to Cairo bytecode executed
with the Cairo VM
2024-03-27 10:40:24 +01:00
Łukasz Czajka
7d559b1f18
CASM serialization (#2679)
* Closes #2563 

Checklist
------------

- [x] Serialization of the Haskell CASM representation to the JSON
format accepted by the Cairo VM.
- [x] Add the `cairo` target to the `compile` commands.
- [x] Output via the Cairo `output` builtin.
- [x] Relativize jumps. Cairo VM doesn't actually support absolute
jumps.
- [x] Test the translation from CASM to Cairo by running the output in
the Cairo VM
- [x] Add Cairo VM to the CI
2024-03-26 17:18:52 +01:00
Paul Cadman
29f1c4c4df
Release 0.6.1 (#2699)
This PR updates:

- [x] Package version
- [x] Smoke test
- [x] Changelog
2024-03-25 11:45:18 +00:00
Paul Cadman
b981405e45
Support compilation of Anoma transactions in nockma backend (#2693)
When we first implemented the Nockma backend we wrongly assumed that the
only entry point for Juvix compiled Nockma modules would be the main
function. Using this assumption we could add a setup step in the main
function that put the Anoma stdlib and compiled functions from the Juvix
module in a static place in the Nockma subject. References to the Anoma
stdlib and functions in the module could then be resolved statically.

However, one of the use cases for Juvix -> Nockma compilation is for
Anoma to run logic functions that are fields of a transaction. So the
user writes a Juvix program with main function that returns a
transaction. The result of the main function is passed to Anoma. When
Anoma calls the logic function on a field of the transaction, the setup
part of the main function is not run so the subject is not in the
required state. In fact, the logic function is not even callable by
Anoma because non-main functions in the Juvix module use a calling
convention that assumes the subject has a particular shape.

This PR solves the problem by making all functions in the Juvix module
use the Anoma calling convention. We make all compiled closures
(including, for example, the logic functions stored on resources in a
transaction) self contained, i.e they contain the functions library and
anoma standard library.

Modules that contain many closures produce large nockma output files
which slows down the evaluator. This will need to be fixed in the future
either with Nockma compression ([jam
serialization](https://developers.urbit.org/reference/hoon/stdlib/2p))
or otherwise. But it does not block the compilation and execution of
Anoma transactions.

Other fixes / additions:

* Extra tracing. You can now annotate output cells with a tag that will
be displayed in the output
* Unittests for listToTuple, appendRights helper functions
* Fixes for the nockma parser when parsing 'pretty nockma', specifically
stdlib calls, tags and functions_library atom.
* Adds `juvix dev nock run` command that can run a program output with
the `anoma` target.
* Remove the `nockma` target. As described above we always use the Anoma
calling convention so there's no need for a separate target for the
'juvix calling convention'
* Adds a `--profile` flag to `juvix dev nock run` which outputs a count
of Nockma ops used in the evaluation
* In tests we no longer serialise the compiled program to force full
evaluation of the compiled code. We added a negative test to check that
strings are not allowed in Nockma/Anoma programs,

it is output in a file `OUTPUT.profile` and has the following form:

```
quote : 15077
apply : 0
isCell : 0
suc : 0
= : 4517
if : 5086
seq : 5086
push : 0
call : 4896
replace : 1
hint : 8
scry : 0
trace : 0
```

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-03-22 23:03:38 +01:00
Paul Cadman
2e006421a5
Support nockma scry (#2678)
This PR adds support for Anoma/Nockma scry OP. It is used for obtaining
values from the Anoma storage (key value store). See the [linked
issue](https://github.com/anoma/juvix/issues/2672) for details on scry.

This PR adds support for scry to the Nockma language and compilation
from the frontend via a builtin: `anoma-get`:

```
builtin anoma-get
axiom anomaGet : {Value Key : Type} -> Key -> Value
```

In the backend, the `Value` and `Key` types could be anything, they will
depend on choices of Anoma applications. The type of the returned
`Value` is unchecked. It's currently the responsibility of the user to
match the annotated type with the type of data in storage.

We will not put this builtin in the standard library. It will be exposed
in the anoma-juvix library. It's likely that the frontend `anomaGet`
function will evolve as we use it to write Anoma applications and learn
how they work.

* Closes https://github.com/anoma/juvix/issues/2672

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-03-21 16:44:14 +01:00
Łukasz Czajka
0f713c7c84
JuvixReg to CASM translation (#2671)
* Closes #2562 

Checklist
---------

- [x] Translation from JuvixReg to CASM
- [x] CASM runtime
- [x] Juvix to CASM pipeline: combine the right transformations and
check prerequisites
- [x] CLI commands: add target `casm` to the `compile` commands
- [x] Tests:
   - [x] Test the translation from JuvixReg to CASM
   - [x] Test the entire pipeline from Juvix to CASM
2024-03-20 12:14:12 +01:00
Jonathan Cubides
ff853b51ba
Add flags for the markdown and html backend: --strip-prefix and --ext. (#2681)
This PR adds some flags to tune the (html/md) output.

For Markdown subcommand:


```
 --strip-prefix ARG       Strip the given prefix from the input file path for
                           HTML hyperlinks
 --folder-structure       Generate HTML following the module's folder structure 
```

For HTML subcommand, we have the ones above plus the following:

```
 --ext ARG                File extension in hyperlinks for the input file
                           (default: ".html")
```
2024-03-09 18:42:09 +01:00
Paul Cadman
a866742872
Release v0.6.0 (#2676)
This PR updates:

- [x] Package version
- [x] Smoke test
- [x] Changelog
2024-03-01 09:14:32 +00:00
Łukasz Czajka
dcea0bbecb
Add field element type (#2659)
* Closes #2571
* It is reasonable to finish this PR before tackling #2562, because the
field element type is the primary data type in Cairo.
* Depends on #2653

Checklist
---------

- [x] Add field type and operations to intermediate representations
(JuvixCore, JuvixTree, JuvixAsm, JuvixReg).
- [x] Add CLI option to choose field size.
- [x] Add frontend field builtins.
- [x] Automatic conversion of integer literals to field elements.
- [x] Juvix standard library support for fields.
- [x] Check if field size matches when loading a stored module.
- [x] Update the Cairo Assembly (CASM) interpreter to use the field type
instead of integer type.
- [x] Add field type to VampIR backend.
- [x] Tests

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-02-27 14:54:43 +01:00
Paul Cadman
a091a7f63d
Update REPL artifacts with builtins from stored modules (#2639)
Builtin information needs to be propagated from stored modules to REPL
artifacts to avoid "The builtin _ has not been defined" errors.

This PR adds a test suite for the REPL in the Haskell test code. This
means some of the slow smoke tests can be moved to fast haskell unit
tests. In future we should refactor the REPL code by putting in the main
src target and unit testing more features (e.g :doc, :def).

* Closes https://github.com/anoma/juvix/issues/2638
2024-02-26 16:19:04 +00:00
Paul Cadman
346b18fd67
Use the target of aliases when resolving name signatures and iterators (#2669)
* Closes https://github.com/anoma/juvix/issues/2664

As well as this fix we rename lens scopedIdenName to scopedIdenSrcName.
`scopedIdenSrcName` refers to the name of an identifier from the source
code. The name `scopedIdenName` is confusing because users of
`ScopedIden` may think that this lens refers to the only name associated
with `ScopedIden`, they may want `scopedIdenNameFinal` instead.
2024-02-26 11:53:47 +00:00
Paul Cadman
be24abb0ca
Support compilation to Anoma compatible functions (#2652)
This PR adds a `anoma` target to the `juvix compile`. This target
compiles a Juvix `main` function to a Nockma/Anoma "function". Unlike
the native, wasm, and nockma targets the main function may have any type
signature.

## Anoma calling convention

[Anoma calls
functions](6a4e15fe9c/lib/anoma/resource.ex (L122))
by evaluating the formula `[call L replace [RL args] @ S]` against a
subject equal to the function. Here `args` is a Nockma term that
evaluates to a tuple of arguments that should be passed to the function.

The anoma target compiles the `main` function to Nockma in the same way
as the nockma target. The main function is then
[wrapped](9a658465ae/src/Juvix/Compiler/Nockma/Translation/FromTree.hs (L627))
to make it compatible with the Anoma calling convention.

## Testing

The anoma calling convention is [unit
tested](9a658465ae/test/Nockma/Eval/Positive.hs (L117))
and [smoke
tested](9a658465ae/tests/smoke/Commands/compile.smoke.yaml (L159)).

This PR also adds versions of the end-to-end compilation tests. Most
tests are included, tests for builtin IO operations and string builtins
are omitted. Other tests that use Strings have been adapted to use other
types that are compatible with this backend.

## Nockma REPL

To facilitate testing the Nockma REPL can now load a nockma file as an
initial subject.

---------

Co-authored-by: Lukasz Czajka <lukasz@heliax.dev>
2024-02-23 12:54:22 +00:00
Łukasz Czajka
cb808c1696
Transform JuvixReg into SSA form (#2646)
* Closes #2560 
* Adds a transformation of JuvixReg into SSA form.
* Adds an "output variable" field to branching instructions (`Case`,
`Branch`) which indicates the output variable to which the result is
assigned in both branches. The output variable corresponds to top of
stack in JuvixAsm after executing the branches. In the SSA
transformation, differently renamed output variables are unified by
inserting assignment instructions at the end of branches.
* Adds tests for the SSA transformation.
* Depends on #2641.
2024-02-20 11:45:14 +01:00
Paul Cadman
a1264643b2
Correctly resolve the visibility annotations of NameSpaceEntries (#2657)
See the bug report for context.

* Closes #2656
2024-02-16 18:26:01 +01:00
Paul Cadman
dc0498902f
Transitively register local modules in ScoperState (#2655)
This PR fixes a TODO in the scoper code. We need to transitively
register local modules when checking an import.


* Closes #2654
2024-02-16 14:09:49 +00:00
Jan Mas Rovira
50a62f6182
Fix bugs in the Nockma prettyprinter and parser (#2632)
This pr addresses a number of problems.

1. It fixes a bug where paths were annotated as operations rather than
paths in the parser.
2. It fixes a bug that happened when unfolding cells in the pretty
printer in order to minimize delimiters. It caused the stdlibcall hints
to be ignored for the unfolded arguments.
3. In order to properly test this, we can't ignore the hints for the Eq
instance, so I've changed that.
4. I've introduced the class NockmaEq for nockma semantic equality. This
is used in the evaluator as well as in the semantic tests.
5. I've added a bigger test. I found these bugs while working with this
file.
2024-02-09 14:59:42 +01:00
Łukasz Czajka
ed15e57d8a
JuvixReg parser and pretty printer (#2617)
* Closes #2578 
* Implements JuvixReg parser and pretty printer.
* Adds the `juvix dev reg read file.jvr` command.
* Adds the `reg` target to the `compile` commands.
* Adds tests for the JuvixReg parser.
2024-02-09 12:19:29 +01:00
Łukasz Czajka
795212b092
JuvixTree validation (#2616)
* Validation (type checking) of JuvixTree. Similar to JuvixAsm
validation, will help with debugging.
* Depends on #2608
2024-02-06 15:46:55 +01:00
Jan Mas Rovira
10e2a23239
Translation from Juvix Tree to Nockma (#2614)
This PR replaces the JuvixAsm -> Nockma translation with a JuvixTree ->
Nockma translation.

We can now enable some of the JuvixTree tests that did not work with
JuvixAsm->Nockma because they were too slow.


## Notes

We have changed [test031: temp stack with
branching](22ee87f0e7/tests/Tree/positive/test031.jvt)
to avoid using negative numbers (because negative integers are not
supported in Nockma).

Three tree tests trace/output lists. Lists are serialised differently by
the asm and nockma pretty printers so they cannot share a single test
output file. We have created separate nockma output files for these
tests (see eg.
[test028.nockma.out](22ee87f0e7/tests/Tree/positive/out/test028.nockma.out)).

* Closes https://github.com/anoma/juvix/issues/2606

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
Co-authored-by: Lukasz Czajka <lukasz@heliax.dev>
2024-02-06 08:33:14 +00:00
Łukasz Czajka
7b0a11d570
JuvixTree negative evaluation tests (#2601)
* Adds negative tests for the JuvixTree evaluator
* Depends on #2600 
* Depends on #2599 
* Depends on #2598 
* Depends on #2597 
* Depends on #2596 
* Depends on #2595 
* Depends on #2594 
* Depends on #2590
2024-02-01 12:58:38 +00:00
Paul Cadman
ab887e3138
Store syntax aliases in serialized scoper infotable (#2605)
This PR fixes an issue with importing `syntax alias` and using them from
another module:

Say you have a module defining a syntax alias:

```
module SyntaxAlias;

import Stdlib.Prelude open;

syntax alias MyNat := Nat;
```

and another which imports / uses it:

```
module test073;

import SyntaxAlias open;

main : MyNat := 11;
```

The compiler crashed with the following error:

```
^?!): empty Fold
            CallStack (from HasCallStack):
              error, called at src/Lens/Micro.hs:711:28 in microlens-0.4.13.1-ARwI8t2x86cAxRs56XPcG1:Lens.Micro
              ^?!, called at src/Juvix/Compiler/Concrete/Translation/FromParsed/Analysis/Scoping.hs:565:29 in juvix-0.5.5-G7jC6MbkbsJGkMT9u4BkYQ:Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping
```

We fix this by adding the aliases to the store's [scoper info
table](6649209d26/src/Juvix/Compiler/Store/Scoped/Data/InfoTable.hs (L14))
and then use it to initialise the scoper state when scoping a module.
2024-01-31 11:56:09 +00:00
Łukasz Czajka
dc54bbb2c2
JuvixTree smoke tests (#2598)
* Adds smoke tests for `juvix dev tree` CLI commands.
* Fixes a bug with printing JuvixAsm.
* Depends on #2597 
* Depends on #2596 
* Depends on #2595 
* Depends on #2594 
* Depends on #2590
2024-01-31 08:33:52 +00:00
Łukasz Czajka
15c223d0f1
Filter out unreachable functions in JuvixTree (#2597)
* Adds the `FilterUnreachable` transformation in JuvixTree.
* Depends on #2596 
* Depends on #2595 
* Depends on #2594 
* Depends on #2590 
* Depends on #2589 
* Depends on #2587
2024-01-30 20:01:07 +00:00
Łukasz Czajka
c95fcb38c8
JuvixTree tests (#2587)
* Implements a translation from JuvixAsm to JuvixTree. It does not work
in general, but works for all code generated from Juvix and all JuvixAsm
tests.
* Adds the `juvix dev tree from-asm` command.
* Adds tests automatically converted from JuvixAsm tests.
* Depends on #2583
2024-01-25 18:02:06 +00:00
Łukasz Czajka
e5ea085f1c
JuvixTree parser and pretty printer (#2583)
This PR implements:
* JuvixTree parser.
* JuvixTree pretty printer.
* `juvix dev tree read file.jvt` command which reads and pretty prints a
JuvixTree file.
* The `tree` target in the `compile` command.
* Removal of `StackRef` in JuvixAsm. This makes JuvixAsm more consistent
with JuvixTree and simplifies the data structures. `StackRef` is not
needed for compilation from Core.

Tests for the parser will appear in a separate PR, when I implement an
automatic translation of JuvixAsm to JuvixTree files.

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
2024-01-24 12:45:39 +01:00
Jan Mas Rovira
39d176e643
Fast nockma eval (#2580)
Adds annotations to cells to indicate that it is a call to the stdlib
and might be evaluated faster in the Haskell evaluator.

The syntax for stdlib calls is as follows:
```
[stdlib@add args@<args-term> <left-term> <right-term>]
```
where `add` is the name of the function being called, `<args-term>` is a
nockma term that points to the position of the arguments, and
`<left-term>` and `<right-term>` are the actual components of the cell.
2024-01-19 12:01:58 +01:00
Łukasz Czajka
3aaa8229cc
Merge stack and temporary variable groups in JuvixReg (#2579)
After this change there are only two types of variables in JuvixReg:
arguments and local variables. The previous distinction between stack
and temporary variables was spurious and complicated things
unnecessarily.
2024-01-17 19:11:40 +01:00
Łukasz Czajka
fa2a731833
Cairo ASM language and interpreter (#2572)
* Closes #2561 
* Defines an extended subset of Cairo Assembly, following Section 5 of
[1].
* Adds the commands `juvix dev casm read file.casm` and `juvix dev casm
run file.casm` to print and run `*.casm` files.
* The tests cover CASM semantics. Some are "manual translations" of
corresponding JuvixAsm tests according to the JuvixAsm -> CASM
compilation concept.
2024-01-12 11:57:02 +00:00
Łukasz Czajka
3269c8f369
Filter out unreachable functions in JuvixAsm (#2575)
Adds a JuvixAsm transformation to filter out unreachable functions. This
will make the generated nock/cairo code smaller.
2024-01-12 10:48:32 +01:00
Paul Cadman
a9995b8e1c
Add nockma evaluator (#2564)
This PR adds an parser, pretty printer, evaluator, repl and quasi-quoter
for Nock terms.

## Parser / Pretty Printer

The parser and pretty printer handle both standard Nock terms and
'pretty' Nock terms (where op codes and paths can be named). Standard
and pretty Nock forms can be mixed in the same term.

For example instead of `[0 2]` you can write `[@ L]`.

See
a6028b0d92/src/Juvix/Compiler/Nockma/Language.hs (L79)
for the correspondence between pretty Nock and Nock operators.

In pretty Nock, paths are represented as strings of `L` (for head) and
`R` (for tail) instead of the number encoding in standard nock. The
character `S` is used to refer to the whole subject, i.e it is sugar for
`1` in standard Nock.

See
a6028b0d92/src/Juvix/Compiler/Nockma/Language.hs (L177)
for the correspondence between pretty Nock path and standard Nock
position.

## Quasi-quoter

A quasi-quoter is added so Nock terms can be included in the source, e.g
`[nock| [@ LL] |]`.

## REPL

Launch the repl with `juvix dev nockma repl`.

A Nock `[subject formula]` cell is input as `subject / formula` , e.g:

```
nockma>  [1 0] / [@ L]
1
```

The subject can be set using `:set-stack`.

```
nockma> :set-stack [1 0]
nockma> [@ L]
1
```

The subject can be viewed using `:get-stack`.

```
nockma> :set-stack [1 0]
nockma> :get-stack
[1 0]
```

You can assign a Nock term to a variable and use it in another
expression:

```
nockma> r := [@ L]
nockma> [1 0] / r
1
```

A list of assignments can be read from a file:

```
$ cat stack.nock
r := [@ L]
$ juvix dev nockma repl
nockma> :load stack.nock
nockma> [1 0] / r
1
```

* Closes https://github.com/anoma/juvix/issues/2557

---------

Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
Co-authored-by: Lukasz Czajka <lukasz@heliax.dev>
2024-01-11 12:04:38 +00:00
Łukasz Czajka
8e5f45f16f
Require semicolon to separate case/if branches in JuvixAsm syntax (#2574)
This makes the syntax more uniform. It was especially confusing with
nested branching, where some closing braces had to and others couldn't
be followed by a semicolon. Now all have to be followed by a semicolon
(except function ending braces).
2024-01-11 09:19:36 +00:00
Dimitris Apostolou
d6d21a22e3
Fix typos (#2573) 2024-01-08 13:27:18 +01:00
Łukasz Czajka
75bce8f665
Per-module compilation (#2468)
* Closes #2392 

Changes checklist
-----------------
* [X] Abstract out data types for stored module representation
(`ModuleInfo` in `Juvix.Compiler.Store.Language`)
* [X] Adapt the parser to operate per-module
* [X] Adapt the scoper to operate per-module
* [X] Adapt the arity checker to operate per-module
* [X] Adapt the type checker to operate per-module
* [x] Adapt Core transformations to operate per-module
* [X] Adapt the pipeline functions in `Juvix.Compiler.Pipeline`
* [X] Add `Juvix.Compiler.Pipeline.Driver` which drives the per-module
compilation process
* [x] Implement module saving / loading in `Pipeline.Driver`
* [x] Detect cyclic module dependencies in `Pipeline.Driver`
* [x] Cache visited modules in memory in `Pipeline.Driver` to avoid
excessive disk operations and repeated hash re-computations
* [x] Recompile a module if one of its dependencies needs recompilation
and contains functions that are always inlined.
* [x] Fix identifier dependencies for mutual block creation in
`Internal.fromConcrete`
- Fixed by making textually later definitions depend on earlier ones.
- Now instances are used for resolution only after the textual point of
their definition.
- Similarly, type synonyms will be unfolded only after the textual point
of their definition.
* [x] Fix CLI
* [x] Fix REPL
* [x] Fix highlighting
* [x] Fix HTML generation
* [x] Adapt test suite
2023-12-30 20:15:35 +01:00
Łukasz Czajka
758d1cd949
Implement the dynamic dispatch loop in JuvixAsm (#2556)
* Closes #2555 
* Depends on #2554
2023-12-15 19:08:40 +01:00
Łukasz Czajka
76548e464a
Structured temporary stack manipulation in JuvixAsm (#2554)
* Replaces the `pusht` and `popt` instructions with block-based `save`
and `tsave`. This encodes the structure of temporary stack manipulation
syntactically, making it impossible to manipulate it in unexpected ways.
Also simplifies compilation to Nock.
* Adds optional names for temporaries and function arguments.
2023-12-15 12:55:53 +00:00
Paul Cadman
170a4d39c0
Fix benchmarks test compilation (#2552)
The benchmarks build has been broken for some time because one of the
juvix programs was not compiling.
2023-12-10 12:13:56 +01:00
Jan Mas Rovira
d3e862fc51
Improve formatting of function definition arguments (#2551)
- Closes #2534
2023-12-07 11:26:48 +01:00
Jan Mas Rovira
4fa17359a6
Implement wildcard constructor (#2550)
- Closes #2549 

The implementation of wildcard constructors was previously done in the
arity checker. I did not realise I was missing it because there was not
tests for it that included typechecking (we were only checking
formatting).
2023-12-07 10:12:36 +01:00
Jan Mas Rovira
69594edc7b
Read Package on demand and cache it (#2548)
This patch dramatically increases the efficiency of `juvix dev root`,
which was unnecessarily parsing all dependencies included in the
`Package.juvix` file. Other commands that do not require the `Package`
will also be faster.

It also refactors some functions so that the `TaggedLock` effect is run
globally.

I've added `singletons-base` as a dependency so we can have `++` on the
type level. We've tried to define a type family ourselves but inference
was not working properly.
2023-12-06 18:24:59 +01:00
Jonathan Cubides
9f8c26dbb2
Bump up version to v0.5.5 (#2547)
This PR updates:

- [x] Package version
- [x] Smoke test
- [x] Changelog

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-12-01 20:48:35 +01:00
Jan Mas Rovira
c8e7ce8afd
Remove old typechecker (#2545) 2023-12-01 16:50:37 +01:00
Paul Cadman
77b29c6963
Update to the latest juvix-stdlib (#2546)
This PR updates the juvix-stdlib submodule ref to the current
juvix-stdlib/main.

NB: The Markdown test is not stable after changes to the stdlib - the
ids (deriving from internal name ids?) will change and so the expected
file must be regenerated.
2023-12-01 15:12:54 +01:00
Paul Cadman
20a95ec42d
Extract builtin definitions for loading a Package into bundled package-base package (#2535)
This PR creates a new package that's bundled with the compiler in a
similar way to the stdlib and the package description package.

## The `package-base` Package

This package is called
[package-base](ab4376cf9e/include/package-base)
and contains the minimal set of definitions required to load a Package
file.

The
[`Juvix.Builtin`](ab4376cf9e/include/package-base/Juvix/Builtin/V1.juvix)
module contains:

```
module Juvix.Builtin.V1;

import Juvix.Builtin.V1.Nat open public;
import Juvix.Builtin.V1.Trait.Natural open public;
import Juvix.Builtin.V1.String open public;
import Juvix.Builtin.V1.Bool open public;
import Juvix.Builtin.V1.Maybe open public;
import Juvix.Builtin.V1.List open public;
import Juvix.Builtin.V1.Fixity open public;
```

`Juvix.Builtin.V1.Bool` is required to support backend primitive
integers `Juvix.Builtin.V1.Trait.Natural` is required to support numeric
literals.

## The `PackageDescription.V2` module

This PR also adds a new
[`PackageDescription.V2`](ab4376cf9e/include/package/PackageDescription/V2.juvix)
type that uses the `package-base`. This is to avoid breaking existing
Package files. The Packages files in the repo (except those that test
`PackageDescription.V1`) have also been updated.

## Updating the stdlib

The standard library will be updated to use `Juvix.Builtin.*` modules in
a subsequent PR.

* Part of https://github.com/anoma/juvix/issues/2511
2023-11-30 16:22:18 +00:00
Jonathan Cubides
7de9f2f0f3
Add new case for positivity checker: type cannot occur as arg of bound var (#2542)
This PR fixes our positivity checker to support inductive definitions
with type families as type parameters. This kind of ind. type is
type-checked using the global flag `--new-type checker.`

For example, the following definition is not allowed:

```
module Evil;

type Evil (f : Type -> Type) :=
  magic : f (Evil f) -> Evil f;
```

- Closes #2540
2023-11-30 15:03:54 +01:00
Jan Mas Rovira
d6c1a74cec
Improve inference for --new-typechecker (#2524)
This pr applies a number of fixes to the new typechecker.
The fixes implemented are:
1. When guessing the arity of the body, we properly use the type
information of the variables in the patterns.
2. When generating wildcards, we name them properly so that they align
with the name in the type signature.
3. When compiling named applications, we inline all clauses of the form
`fun : _ := body`. This is a workaround to
https://github.com/anoma/juvix/issues/2247 and
https://github.com/anoma/juvix/issues/2517
4. I've had to ignore test027 (Church numerals). While the typechecker
passes and one can see that the types are correct, there is a lambda
where its clauses have different number of patterns. Our goal is to
support that in the near future
(https://github.com/anoma/juvix/issues/1706). This is the conflicting
lambda:
    ```
    mutual num : Nat → Num
      := λ : Nat → Num {| (zero : Nat) := czero
      | ((suc n : Nat)) {A} := csuc (num n) {A}}
    ```
5. I've added non-trivial a compilation test involving monad
transformers.
2023-11-28 16:43:14 +01:00
Jonathan Cubides
628dd23072
Fix codeblocks indentation in Markdown output (#2539)
- Closes https://github.com/anoma/juvix/issues/2528
- Closes https://github.com/anoma/juvix-docs/issues/95

After this PR is merged, this will fix the misbehaving of code blocks
within !!!/??? Environments spotted in
https://github.com/anoma/juvix-docs/issues/95. The result would be
as expected:

Already deployed, e.g. https://docs.juvix.org/0.5.4/tutorials/learn/

![screencapture-localhost-8000-reference-language-functions-2023-11-24-21_28_39](https://github.com/anoma/juvix/assets/1428088/85877b1a-0428-40b2-b900-147b3f386e8c)
2023-11-27 13:22:44 +01:00
Paul Cadman
1c1a5b7117
Update the Juvix lock file when the Package file changes (#2522)
Adds a new version of the lock file that stores the hash (sha256 digest)
of the package file (Package.juvix, juvix.yaml) it was generated from as
a field:

```
# This file was autogenerated by Juvix version 0.5.4.
# Do not edit this file manually.

version: 2
checksum: d05940a4d3dc0e15451d02e1294819c875ba486ee54e26865ba8d190ac7c27c3
dependencies:
- git:
    name: stdlib
    ref: f68b0614ad695eaa13ead42f3466e0a78219f826
    url: https://github.com/anoma/juvix-stdlib.git
  dependencies: []
```

The lock file is regenerated when the hash of the package file doesn't
match the value of the `checksum` field, i.e when the user updates the
package file.

Existing lock files are automatically migrated to version 2.

* Closes https://github.com/anoma/juvix/issues/2464
2023-11-22 23:21:29 +01:00
Paul Cadman
c6586a960d
Fix the global 'package' package so that modules within it can be type-checked independently (#2526)
This PR adds a Package.juvix file to the global 'package' package (that
is the package containing the `PackageDescription.{Basic, V1}` modules.

This means that users can now go-to-definition on Package.juvix types
and identifiers and navigate to fully highlighted
`PackageDescription.{Basic, V1}` modules.

* Closes https://github.com/anoma/juvix/issues/2525
2023-11-21 15:20:00 +00:00
Paul Cadman
8bbf089d63
Release 0.5.4 (#2523)
This PR updates:
- [x] Package version
- [x] Smoke test
- [x] Changelog
2023-11-17 16:47:00 +00:00
Jonathan Cubides
dd43f07905
Fix #2510 (#2512)
- Close #2510 
- Close #2518 
- Progress for #2520
2023-11-17 16:10:38 +01:00
Jonathan Cubides
8616370fb2
Add MarkdownInfo entry in Module Concrete Decl and proper errors (#2515)
Remove TODO added by @janmasrovira in 
- https://github.com/anoma/juvix/pull/2513
2023-11-16 11:20:34 +01:00
Jan Mas Rovira
90200ab6de
General inductive parameters (#2506)
- Depends on #2481 

This pr allows inductive type parameters to be any type. Until now, they
had to be exactly `Type`. This allows us to define more general traits
such as the `Monad` and `Functor`, as shown in the new test.
This is only supported under the temporary `--new-typechecker` flag.

Pending work:

Update the positivity checker if necessary (@jonaprieto).
Update the necessary compilation steps in Core (@lukaszcz).
Add compilation tests.
2023-11-15 10:24:54 +01:00
Paul Cadman
7b5211664e
Add PackageDescription.Basic module Package variant (#2509)
This PR adds the `PackageDescription.Basic` module, available to
Package.juvix files.

```
module Package;

import PackageDescription.Basic open;

package : Package := basicPackage;
```

The `PackageDescription.Basic` module provides a Package type that is
translated to a Juvix Package with all default arguments. It is not
possible to customize a basic package.

A basic package does not depend on the standard library, so loads much
more quickly.

Additionally this PR:
* Adds `juvix init --basic/-b` option to generate a basic Package.juvix.
* Migrates Package.juvix files that only use default arguments, or only
customise the name field, to basic Package files.

* Closes https://github.com/anoma/juvix/issues/2508
2023-11-13 17:36:18 +00:00
Jonathan Cubides
bd16d3ef2a
Add support for Literate Juvix Markdown (#2448)
This PR adds an initial support for Literate Juvix Markdown files, files
with the extension `.juvix.md`.

Here is a small example of such a file: `Test.juvix.md`.

<pre>
# This is a heading
Lorem ...

```juvix
module Test;

type A := a;

fun : A -> A 
 | _ := a;
```
Other text
</pre>


This initial support enables users to execute common commands such as
typechecking, compilation, and HTML generation. Additionally, a new
command called `markdown` has been introduced. This command replaces
code blocks marked with the juvix attribute with their respective HTML
output, much like the output we obtain when running `juvix html`. In
this version, comments are ignored in the output, including judoc
blocks.

- We intend to use this new feature in combination with this Python
plugin (https://github.com/anoma/juvix-mkdocs) to enhance our
documentation site.



https://github.com/anoma/juvix/assets/1428088/a0c17f36-3d76-42cc-a571-91f885866874


## Future work

Open as issues once this PR is merged, we can work on the following:

- Support imports of Juvix Markdown modules (update the path resolver to
support imports of Literate Markdown files)
- Support (Judoc) comments in md Juvix blocks
- Support Markdown in Judoc blocks
- Update Text editor support, vscode extension and emacs mode (the
highlighting info is a few characters off in the current state)



- Closes #1839 
- Closes #1719
2023-11-10 13:55:36 +01:00
Paul Cadman
68d4314c78
Migrate all Juvix projects from juvix.yaml to Package.juvix in the repository (#2503)
This PR:

* Modifies entry point `_entryPointBuildDir` to use the `BuildDir` type
instead of `SomeBase Dir`. This allows delayed resolution of the default
build directory which was useful for the Package -> Concrete translation
point below.
* Modifies `juvix dev root` to render the current package as a
Package.juvix file.
* Modifies the Package -> Concrete translation to recognise default
arguments. So, for example, an empty `juvix.yaml` file will be
translated into the following (instead of the `name`, `version`, and
`dependencies` arguments being populated).

        
        module Package;

        import Stdlib.Prelude open;
        import PackageDescription.V1 open;

        package : Package := defaultPackage;
        
* Adds a temporary command (removed when juvix.yaml support is removed)
`juvix dev migrate-juvix-yaml` that translates `juvix.yaml` into an
equivalent `Package.juvix` in the current project.
* Adds a temporary script `migrate-juvix-yaml.sh` (removed when
juvix.yaml support is removed) which can be run in the project to
translate all Juvix projects in the repository.
* Actually translate all of the `juvix.yaml` files to `Package.juvix`
using the script.

* Part of https://github.com/anoma/juvix/issues/2487
2023-11-07 18:11:02 +00:00
Łukasz Czajka
5948a38a54
Named arguments syntax with function definitions (#2494)
* Closes #2365
* Implements the syntax `f@{x1 := def1; ...; xn := defn}` and `f@?{x1 :=
def1; ..; xn := defn}`. Each definition inside the `@{..}` is an
ordinary function definition. The `@?` version allows partial
application (not all explicit named arguments need to be provided). This
subsumes the old record creation syntax.
2023-11-07 12:02:22 +01:00
Paul Cadman
9690aadf53
Update file walker to use Package.juvix to detect a Juvix package (#2502)
The file walker `RecurseFilter` indictates if the the walker recurses
into
a directory which contains a Juvix project.

Previously the file walker would detect juvix.yaml. It now detects both
juvix.yaml and Package.juvix.

* Part of https://github.com/anoma/juvix/issues/2487
2023-11-06 15:34:27 +00:00
Paul Cadman
e8a5d20d07
Add -n/--non-interactive option to juvix init (#2500)
When moving to Package.juvix, the package configuration file cannot be
empty. So it's convenient to have a quick way to create a Package.juvix
file (previously you could run `touch juvix.yaml`.

This PR adds the `-n / --non-interactive` option to `juvix init`. This
will create a default `Package.juvix`, using the name of the current
directory to populate the package name.

Similarly for the interactive version of juvix init, if the name of the
current directory is not a valid Juvix module then a fallback name is
used instead.

For example:
```
$ mkdir /tmp/new-package
$ cd /tmp/new-package
$ juvix init -n
$ cat Package.juvix
module Package;

import PackageDescription.V1 open;

package : Package :=
  defaultPackage
    {name := "new-package";
     version := mkVersion 0 0 0;
     dependencies := [defaultStdlib]};
```

* Part of https://github.com/anoma/juvix/issues/2487
2023-11-06 13:56:20 +00:00
Paul Cadman
511e99f217
Use Package.juvix in the global project (#2499)
## Global package configuration

This PR updates the global-project to use `Package.juvix` instead of
`juvix.yaml`.

The global package gets the following `Package.juvix`:

```
module Package;

import PackageDescription.V1 open;

package : Package :=
  defaultPackage
    {name := "global-juvix-package";
     version := mkVersion 0 0 0;
     dependencies := [defaultStdlib]};
```

## juvix clean --global

This PR also adds an option `-g/--global` to `juvix clean` that removes
the `$XDG_CONFIG_HOME/juvix/VERSION` directory.

## Testing notes

If you've already run Juvix 0.5.3 you'll need to run `juvix clean -g`
before you'll use the new global project. This will not be an issue for
users of Juvix 0.5.4 (as this version of Juvix will never generate
juvix.yaml in the global project).

Part of:
* https://github.com/anoma/juvix/issues/2487
2023-11-06 11:49:43 +00:00
Paul Cadman
9d75dcac96
Normalise paths on ResolverCache set and lookup (#2498)
Paths are used as keys in the PathResolver ResolverCache. These paths
must be normalised because a path may have a different representation
when it is used to set an entry in the cache and when it is used to
lookup from the cache.

Path normalisation is also used in the REPL before a directory is
compared with the standard library path.

* Closes https://github.com/anoma/juvix/issues/2497
2023-11-06 09:45:26 +00:00
Jonathan Cubides
ee45ddf8c2
Fix #2495 (#2496)
- Closes #2495
2023-11-03 21:23:57 +01:00
Jonathan Cubides
47c8df11f1
Fix remove unexpected whitespaces introduced by formatting (#2489)
- Closes #2059
2023-11-03 12:51:45 +01:00
Paul Cadman
145f20fc68
Update juvix init to generate Package.juvix instead of juvix.yaml (#2483)
`juvix init` now generates a `Package.juvix` file in the current
directory instead of a `juvix.yaml` file. It uses the prompts from the
user to fill in the name and version options.

### Validity check

After the file is generated, the Juvix project in the current directory
is loaded to check that the generated file is valid.

### Version support

Each version of the PackageDescription module must have a corresponding
[PackageDescriptionType](c39c27000c/src/Juvix/Compiler/Pipeline/Package/Loader/Versions.hs (L12))
which defines:

* The path relative to `include/package` that the file exists at (e.g
`PackageDescription/V1.juvix`)
* The name of the Package type in the file (e.g `Package`)
* A function that translates a Package type into a Concrete function
definition that represents the code that is generated in the
`Package.juvix`
* A function that returns a Bool that determines if the generated
function definition depends on the standard library. (i.e that the
standard library needs to be imported by Package.juvix).

The last point is necessary because in the V1 spec, the `SemVer` type
uses `Maybe` to encode the release and meta components of the of the
version:

```
package : Package :=
  defaultPackage
    {name := "dd";
     version := mkVersion 1 2 3 {just "prerel"} {just "meta"}};
```

So if the user specifies a release or meta component in their version -
then the standard library needs to be imported to provide the `just`
constructor. If the user only specifies major, minor and patch
components then the standard library does not need to be imported.

* Closes https://github.com/anoma/juvix/issues/2485
2023-11-03 09:54:44 +00:00
Łukasz Czajka
485f6e7920
Literal casting (#2457)
* Closes #2453 
* Closes #2432
* Any nonnegative literal `n` is replaced with `fromNat {_} {{_}} n`
where `fromNat` is the builtin conversion function defined in the
`Natural` trait in `Stdlib.Trait.Natural`.
* Any negative literal `-n` is replaced with `fromInt {_} {{_}} -n`
where `fromInt` is the builtin conversion function defined in the
`Integral` trait in `Stdlib.Trait.Integral`.
* Before resolving instance holes, it is checked whether the type holes
introduced for `fromNat` and `fromInt` have been inferred. If not, an
attempt is made to unify them with `Nat` or `Int`. This allows to
type-check e.g. `1 == 1` (there is no hint in the context as to what the
type of `1` should be, so it is decided to be `Nat` after inferring the
hole fails).
2023-11-03 10:01:03 +01:00
Paul Cadman
8c5bf822ed
Bump version to 0.5.3 (#2492)
This PR updates:
- [x] Package version
- [x] Smoke test
- [x] Changelog
2023-11-01 16:18:33 +00:00
Jonathan Cubides
21d5034e60
Fix formatting for all Juvix files in tests folder (#2404)
In this PR, we ran the Juvix formatter so that we can now freely run
`make format`, `make check`, or `make pre-commit` without any unexpected
file changes.

This goes after:

- https://github.com/anoma/juvix/pull/2486
2023-10-31 18:36:34 +01:00
Jonathan Cubides
89d35637ac
Fix #2479 (#2486)
Fix formatting for as-patterns inside implicit patterns.
2023-10-31 16:57:27 +01:00
Paul Cadman
9bfe20e323
Version the PackageDescription module (#2478)
This PR adds a version number to the module name of the
`PackageDescription` module. This allows us to change the Package file
format in a backwards compatible way in the future.

Now the simplest Package.juvix file looks like:

```
module Package;

import PackageDescription.V1 open;

package : Package := defaultPackage;
```

## Adding new versions

The idea is that new versions of the PackageDescription format will be
added as files of the form:
include/package/PackageDescription/Vx.juvix

The correspondence between a version of the PackageDescription file and
the package type name is recorded in
[`packageDescriptionTypes`](9ba869d836/src/Juvix/Compiler/Pipeline/Package/Loader.hs (L15)).

The `package` identifier type must come from **one** of the versions
of the PackageDescription module.

* Closes https://github.com/anoma/juvix/issues/2452
2023-10-30 11:33:36 +00:00
Paul Cadman
2e727cc337
Format long list literals by splitting using pre-comma multiline (#2477)
### Example of nested list formatting using the new method:

```
l : List (List Int) :=
  [ [1; 2; 3]
  ; longLongLongListArg
  ; [ longLongLongListArg
    ; longLongLongListArg
    ; longLongLongListArg
    ; longLongLongListArg
    ]
  ; longLongLongListArg
  ];
```

* Closes https://github.com/anoma/juvix/issues/2466
2023-10-30 10:09:48 +01:00
Paul Cadman
0a8799a344
Use a Juvix source file to define a package (#2434)
Depends on:
* ~~https://github.com/anoma/juvix/pull/2459~~
* https://github.com/anoma/juvix/pull/2462

This PR is part of a series implementing:
* https://github.com/anoma/juvix/issues/2336

This PR adds the package file loading function, including a file
evaluation effect. It integrates this with the existing `readPackage`
function and adds tests / smoke tests.

## Package.juvix format

Instead of `juvix.yaml` (which is still supported currently) users can
now place a `Package.juvix` file in the root of their project. The
simplest `Package.juvix` file you can write is:

```
module Package;

import PackageDescription open;

package : Package := defaultPackage;
```

The
[PackageDescription](35b2f618f0/include/package/PackageDescription.juvix)
module defines the `Package` type. Users can use "go-to definition" in
their IDE from the Package file to see the documentation and
definitions.

Users may also import `Stdlib.Prelude` in their Package file. This is
loaded from the global project. No other module imports are supported.

Notes:
* If a directory contains both `Package.juvix` and `juvix.yaml` then
`Package.juvix` is used in preference.

## Default stdlib dependency

The `Dependency` type has a constructor called `defaultStdlib`. This
means that any project can use the compiler builtin standard library
dependency. With `juvix.yaml` this dependency is only available when the
`dependencies` field is unspecified.

```
module Package;

import PackageDescription open;

package : Package := defaultPackage { dependencies := [defaultStdlib] };
```

## Validation

As well as the standard type checking validation that the Juvix compiler
provides additional validation is made on the file.

* The Package module must contain the identifier `package` and it must
have type `Package` that's obtained from the global `PackageDescription`
module.
* Every dependency specified in the Package.juvix must be unique.

* Closes https://github.com/anoma/juvix/issues/2336

## Examples

### Package with name and version

```
module Package;

import PackageDescription open;

package : Package :=
  defaultPackage {name := "a-package";
                  version := mkVersion 0 1 0};
```

### Package with GitHub dependency

```
module Package;

import PackageDescription open;

package : Package :=
  defaultPackage {name := "a-package";
                  version := mkVersion 0 1 0;
                  dependencies := [defaultStdlib;
                                   github (org := "anoma";
                                           repo := "juvix-containers";
                                           ref := "v0.7.1")]};
```

## Package with main and buildDir fields

```
module Package;

import Stdlib.Prelude open;
import PackageDescription open;

package : Package :=
  defaultPackage {name := "a-package";
                  version := mkVersion 0 1 0;
                  dependencies := [defaultStdlib;
                                   github (org := "anoma";
                                           repo := "juvix-containers";
                                           ref := "v0.7.1")];
                  buildDir := just "/tmp/build";
                  main := just "HelloWorld.juvix"
                };

```
2023-10-27 12:35:20 +01:00
Jan Mas Rovira
0943a4ab92
Dependent default values (#2446)
- Closes #2445
2023-10-27 10:19:07 +02:00
Paul Cadman
9a4c09ac77
Add missing juvix.yaml files to test project roots (#2474)
If you have `juvix.yaml` file in a parent of the juvix source directory
in your filesystem then some Compilation tests will fail. This is
because the tests assume that the project root will be in the test
directory.

This PR just adds `juvix.yaml` files to those test directories to avoid
this issue.

Spotted by @agureev
2023-10-26 10:41:23 +01:00
Łukasz Czajka
ef1148beaa
Fix precedence inconsistency bug (#2470)
Precedence inconsistency was not always correctly detected.
2023-10-25 16:13:27 +02:00
Paul Cadman
27aaf9d9f9
Add dependency on expressions in function default arguments (#2462)
Closes:
* https://github.com/anoma/juvix/issues/2461
2023-10-24 11:02:24 +02:00
Paul Cadman
8e6c1c8f07
Use JuvixError instead of Text for errors in Package file loading (#2459)
Depends on:
*  https://github.com/anoma/juvix/pull/2458

This PR is part of a series implementing:
* https://github.com/anoma/juvix/issues/2336

In attempt to make the main PR:
* https://github.com/anoma/juvix/pull/2434
easier to review.

This PR introduces standard JuvixError handling for errors related to
the loading of the juvix.yaml file. Before this PR errors were thrown as
Text and then communicated to the user using the `error` function.
2023-10-23 19:01:36 +01:00
Jonathan Cubides
c6b3b95db3
Add new flags to the Html backend (#2447)
This PR adds `--prefix-id`, `--no-path`, and `only-code` flags to the
HTML backend to manipulate the hyperlinks on the resulting HTML output
and the output itself by only keeping the content of the body in the
Html.

As a usage case, we can support `juvix-standalone` blocks, as
demonstrated in

- https://github.com/anoma/juvix-docs/pull/80
2023-10-23 16:22:04 +02:00
Łukasz Czajka
cdfb35aaac
Arithmetic simplification (#2454)
Simplifies arithmetic expressions in the Core optimization phase,
changing e.g. `(x - 1) + 1` to `x`. Such expressions appear as a result
of compiling pattern matching on natural numbers.
2023-10-23 11:47:17 +02:00
Paul Cadman
c1c2a06922
Process $root/Package.juvix using a special PathResolver (#2451)
The special PathResolver puts files from the global package stdlib and
files from the global package description files in scope of the
$root/Package.juvix module.

Currently this means that PackageDescription module is in scope for the
module so that the user can write:

```
module Package;

import Stdlib.Prelude open;
import PackageDescription open;

package : Package :=
  mkPackageDefault
    (name := "foo")
    { version := mkVersion 0 1 0
    ; dependencies :=
      [ github "anoma" "juvix-stdlib" "adf58a7180b361a022fb53c22ad9e5274ebf6f66"
      ; github "anoma" "juvix-containers" "v0.7.1"]};
```
2023-10-23 10:08:44 +02:00
Łukasz Czajka
272b93e595
Constant folding (#2450)
* Closes #2154 
* Evaluates closed applications with value arguments when the result
type is zero-order. For example, `3 + 4` is evaluated to `7`, and `id 3`
is evaluated to `3`, but `id id` is not evaluated because the target
type is not zero-order (it's a function type).
2023-10-20 12:03:56 +02:00
Łukasz Czajka
cbd8253afd
Instance coercions (#2444)
* Closes #2426 

A coercion from trait `T` to `T'` can be declared with the syntax
```
coercion instance
coeName {A} {{T A}} : T' A := ...
```
Coercions can be seen as instances with special resolution rules.

Coercion resolution rules
-------------------------
* If a non-coercion instance can be applied in a single instance
resolution step, no coercions are considered. No ambiguity results if
there exists some coercion which could be applied, but a non-coercion
instance exists - the non-coercion instances have priority.
* If no non-coercion instance can be applied in a single resolution
step, all minimal coercion paths which lead to an applicable
non-coercion instance are considered. If there is more than one,
ambiguity is reported.

Examples
----------

The following type-checks because:
1. There is no non-coercion instance found for `U String`.
2. There are two minimal coercion paths `U` <- `U1` and `U` <- `U2`, but
only one of them (`U` <- `U2`) ends in an applicable non-coercion
instance (`instU2` for `U2 String`).

```
trait
type U A := mkU {pp : A -> A};

trait
type U1 A := mkU1 {pp : A -> A};

trait
type U2 A := mkU2 {pp : A -> A};

coercion instance
fromU1toU {A} {{U1 A}} : U A :=
  mkU@{
    pp := U1.pp
  };

coercion instance
fromU2toU {A} {{U2 A}} : U A :=
  mkU@{
    pp := U2.pp
  };

instance
instU2 : U2 String := mkU2 id;

main : IO := printStringLn (U.pp "X")
```

The following results in an ambiguity error because:
1. There is no non-coercion instance found for `T Unit`.
2. There are two minimal coercion paths `T` <- `T1` and `T` <- `T2`,
both of which end in applicable non-coercion instances.

```
trait
type T A := mkT { pp : A → A };

trait
type T1 A := mkT1 { pp : A → A };

trait
type T2 A := mkT2 { pp : A → A };

instance
unitT1 : T1 Unit := mkT1 (pp := λ{_ := unit});

instance
unitT2 : T2 Unit := mkT2 (pp := λ{_ := unit});

coercion instance
fromT1toT {A} {{T1 A}} : T A := mkT@{
  pp := T1.pp
};

coercion instance
fromT2toT {A} {{T2 A}} : T A := mkT@{
  pp := T2.pp
};

main : Unit := T.pp unit;
```

The following type-checks, because there exists a non-coercion instance
for `T2 String`, so the coercion `fromT1toT2` is ignored during instance
resolution.

```
trait
type T1 A := mkT1 {pp : A -> A};

trait
type T2 A := mkT2 {pp : A -> A};

instance
instT1 {A} : T1 A :=
  mkT1@{
    pp := id
  };

coercion instance
fromT1toT2 {A} {{M : T1 A}} : T2 A :=
  mkT2@{
    pp := T1.pp {{M}}
  };

instance
instT2 : T2 String :=
  mkT2@{
    pp (s : String) : String := s ++str "!"
  };

main : String := T2.pp "a";
```
2023-10-19 16:00:31 +02:00
Łukasz Czajka
c3bcf40db1
Case value inlining (#2441)
* Introduces the `inline: case` pragma which causes an identifier to be
inlined if it is matched on. This is necessary to support GEB without
compromising optimization for other targets.
* Adapts to the new commits in
https://github.com/anoma/juvix-stdlib/pull/86
2023-10-12 18:59:47 +02:00
Jan Mas Rovira
81f8339625
Allow syntax operator in the rhs of a record declaration (#2442)
- Closes #2431.
2023-10-11 16:59:06 +02:00
Jan Mas Rovira
a5516a5a08
Add default arguments (#2408) 2023-10-10 23:28:06 +02:00
Łukasz Czajka
407a74004c
Fix instance axiom bug (#2439)
* Closes #2438
2023-10-10 15:55:17 +02:00
Łukasz Czajka
60a191b786
Numeric, ordering and equality traits (#2433)
* Adapts to https://github.com/anoma/juvix-stdlib/pull/86
* Adds a pass in `toEvalTransformations` to automatically inline all
record projection functions, regardless of the optimization level. This
is necessary to ensure that arithmetic operations and comparisons on
`Nat` or `Int` are always represented directly with the corresponding
built-in Core functions. This is generally highly desirable and required
for the Geb target.
* Adds the `inline: always` pragma which indicates that a function
should always be inlined during the mandatory inlining phase, regardless
of optimization level.
2023-10-09 18:25:01 +02:00
Jan Mas Rovira
0e4c27b74f
Add constructor wildcards (#2437)
- Closes #2402.

Changes:
1. Allow the definition of empty record types.
2. Introduce the _constructor wildcard_ pattern. That is, a pattern of
the form `constr@{}` that matches the constructor `constr` regardless of
its number of arguments.
2023-10-09 14:14:30 +02:00
Artem Gureev
e7f5a83da3
Update Geb backend (#2436)
Changes in the printing of Lambda terms necessary for the use of the Juvix
Geb backend, changing the names of binary operations, adding a
constructor for natural numbers. Appropriately changes tests when
necessary.

---------

Co-authored-by: Jonathan Cubides <jonathan.cubides@uib.no>
2023-10-06 17:37:08 +02:00
Jan Mas Rovira
28c404348a
Ignore instance arguments in the termination checker (#2435)
- Fixes #2414
2023-10-06 12:09:15 +02:00
Łukasz Czajka
34b5a14935
Improve the specialisation optimisation (#2417)
* Closes #2416 
* Closes #2401 
* Avoids generating identical specialisations by keeping a
specialisation signature for each specialised function application.
* Allows to specialise on a per-trait or per-instance basis:
```
{-# specialize: true #-}
trait
type Natural N := mkNatural {
  + : N -> N -> N;
  * : N -> N -> N;
  fromNat : Nat -> N;
};
```
or
```
{-# specialize: true #-}
instance
naturalNatI : Natural Nat := ...
```
* The above `specialize: bool` pragma actually works with any type or
function. To be able to simultaneously specify the boolean
specialisation flag and specialisation arguments, one can use
`specialize-args: [arg1, .., argn]` which works like `specialize: [arg1,
.., argn]`.
2023-10-05 10:12:48 +02:00
Paul Cadman
b049f931b2
Bump version to 0.5.2 (#2425)
This PR updates:
- [x] Package version
- [x] Smoke test
- [x] Changelog
2023-10-04 13:54:15 +01:00
Łukasz Czajka
6b38543ae3
Fix bug in instance termination checking (#2423)
* Closes #2421
2023-10-04 12:00:48 +02:00
Paul Cadman
76d69b5ef3
Add juvix dependencies update command (#2419)
This PR adds a new command `juvix dependencies update` that fetches all
dependencies in a project and updates the project lock file.

Currently the only way to update the lock file is to delete it and
generate a new one.

## CLI Docs

```
juvix dependencies --help
Usage: juvix dependencies COMMAND

  Subcommands related to dependencies

Available options:
  -h,--help                Show this help text

Available commands:
  update                   Fetch package dependencies and update the lock file
```

## Example

A project containing the following `juvix.yaml`

```yaml
dependencies:
  - .juvix-build/stdlib/
  - git:
      url: https://github.com/anoma/juvix-test
      ref: v0.6.0
      name: test
main: Example.juvix
name: example
version: 1.0.0
```

compile to generate the lockfile: `juvix compile`

```yaml
# This file was autogenerated by Juvix version 0.5.1.
# Do not edit this file manually.

dependencies:
- path: .juvix-build/stdlib/
  dependencies: []
- git:
    name: test
    ref: a94c61749678ff57556ee6e4cb1f8fbbddbc4ab1
    url: https://github.com/anoma/juvix-test
  dependencies:
  - git:
      name: stdlib
      ref: 4facf14d9b2d06b81ce1be1882aa9050f768cb45
      url: https://github.com/anoma/juvix-stdlib
    dependencies: []
```

Now update the test dependency version:

```yaml
- .juvix-build/stdlib/
- git:
   url: https://github.com/anoma/juvix-test
   ref: v0.6.1
   name: test
main: Example.juvix
name: example
version: 1.0.0
```

And run `juvix dependencies update`

Now the lockfile has updated to the hash of v0.6.1:

```yaml
# This file was autogenerated by Juvix version 0.5.1.
# Do not edit this file manually.

dependencies:
- path: .juvix-build/stdlib/
  dependencies: []
- git:
    name: test
    ref: a7ac74cac0db92e0b5e349f279d797c3788cdfdd
    url: https://github.com/anoma/juvix-test
  dependencies:
  - git:
      name: stdlib
      ref: 4facf14d9b2d06b81ce1be1882aa9050f768cb45
      url: https://github.com/anoma/juvix-stdlib
    dependencies: []
```

---------

Co-authored-by: Jonathan Cubides <jonathan.cubides@uib.no>
2023-10-03 18:09:13 +02:00
Jan Mas Rovira
9d9631aa26
Allow open statements in let expressions (#2395)
- Closes #2185
2023-10-02 23:13:45 +02:00
Jan Mas Rovira
76b58f090f
Fix for crash with wildcard used in type definition (#2405)
- Closes #2292.

Holes are now allowed in the type of inductive parameters.
If the type is unsupported, a user error is thrown.
2023-10-02 18:58:21 +02:00
Paul Cadman
dad3963c00
Add package lockfile support (#2388)
This PR adds lock file support to the compiler pipeline. The lock file
is generated whenever a compiler pipeline command (`juvix {compile,
typecheck, repl}`) is run.

The lock file contains all the information necessary to reproduce the
whole dependency source tree. In particular for git dependencies,
branch/tag references are resolved to git hash references.

## Lock file format

The lock file is a YAML `juvix.lock.yaml` file written by the compiler
alongside the package's `juvix.yaml` file.

```
LOCKFILE_SPEC: { dependencies: { DEPENDENCY_SPEC, dependencies: LOCKFILE_SPEC }
DEPENDENCY_SPEC: PATH_SPEC | GIT_SPEC
PATH_SPEC: { path: String }
GIT_SPEC: { git: {url: String, ref: String, name: String } }
```

## Example

Consider a project containing the following `juvix.yaml`:

```yaml
dependencies:
- .juvix-build/stdlib/
- git:
   url: https://github.com/anoma/juvix-containers
   ref: v0.7.1
   name: containers
name: example
version: 1.0.0
```

After running `juvix compile` the following lockfile `juvix.lock.yaml`
is generated.

```yaml
# This file was autogenerated by Juvix version 0.5.1.
# Do not edit this file manually.

dependencies:
- path: .juvix-build/stdlib/
  dependencies: []
- git:
    name: containers
    ref: 3debbc7f5776924eb9652731b3c1982a2ee0ff24
    url: https://github.com/anoma/juvix-containers
  dependencies:
  - git:
      name: stdlib
      ref: 4facf14d9b2d06b81ce1be1882aa9050f768cb45
      url: https://github.com/anoma/juvix-stdlib
    dependencies: []
  - git:
      name: test
      ref: a7ac74cac0db92e0b5e349f279d797c3788cdfdd
      url: https://github.com/anoma/juvix-test
    dependencies:
    - git:
        name: stdlib
        ref: 4facf14d9b2d06b81ce1be1882aa9050f768cb45
        url: https://github.com/anoma/juvix-stdlib
      dependencies: []
```

For subsequent runs of the juvix compile pipeline, the lock file
dependency information is used.

 ## Behaviour when package file and lock file are out of sync

If a dependency is specified in `juvix.yaml` that is not present in the
lock file, an error is raised.

Continuing the example above, say we add an additional dependency:

```
dependencies:
- .juvix-build/stdlib/
- git:
     url: https://github.com/anoma/juvix-containers
     ref: v0.7.1
     name: containers
- git:
     url: https://github.com/anoma/juvix-test
     ref: v0.6.1
     name: test
name: example
version: 1.0.0
```

`juvix compile` will throw an error:

```
/Users/paul/tmp/lockfile/dep/juvix.yaml:1:1: error:
The dependency test is declared in the package's juvix.yaml but is not declared in the lockfile: /Users/paul/tmp/lockfile/dep/juvix.lock.json
Try removing /Users/paul/tmp/lockfile/dep/juvix.lock.yaml and then run Juvix again.
```

Closes:
* https://github.com/anoma/juvix/issues/2334
2023-10-02 17:51:14 +02:00
Łukasz Czajka
5fc0f33bb4
Add Partial trait (#2409)
Adds a Partial trait to the standard library, similar to the one in
PureScript:

https://book.purescript.org/chapter6.html#nullary-type-classes

This enables using partial functions in an encapsulated manner and
without depending on the Debug module.

Adds a trait:

```
trait
type Partial := mkPartial {
   fail : {A : Type} -> String -> A
};

runPartial {A} (f : {{Partial}} -> A) : A := f {{mkPartial Debug.failwith}};
```
2023-10-02 15:14:40 +02:00
Jonathan Cubides
0230a7b848
Fix minor: case and error message (#2407)
Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-09-29 16:28:59 +02:00
Łukasz Czajka
5642c82a0e
Update benchmarks (#2415)
* Small style improvements
* Update `mapfun.juvix` to use `Int` instead of `Nat` so that it is
semantically equivalent to the other implementations.
* Adapt to #2396
2023-09-29 15:55:52 +02:00
Łukasz Czajka
1260853583
Improve closure calls in the runtime (#2396)
* Closes #1653 

The running time improvement is 20-30% on benchmarks dominated by
closure calls.
2023-09-29 14:20:00 +02:00
Łukasz Czajka
7c3b70459b
Fix delay instance resolution (#2393)
* Closes #2348
2023-09-29 13:08:05 +02:00
Łukasz Czajka
e4a5ca7399
Record creation syntax with function definitions (#2369)
* Closes #2280 
* Record creation syntax uses normal function definition syntax like at
the top-level or in lets.
* It is now allowed to omit the result type annotation in function
definitions (the `: ResultType` part) with `_` inserted by default. This
is allowed only for simple definitions of the form `x := value` in lets
and record creation, but not at the top level.
2023-09-28 17:07:38 +02:00
Jonathan Cubides
f9e27b52f7
Update pre-commit to check JSON formatting (#2400) 2023-09-28 14:55:35 +02:00
Jan Mas Rovira
27df3949f5
Add nodes with no edges to the dependency graph (#2390)
- Closes #2373 

Consider this:
```
let 
 x : _ := 0
in ...
```
When translating the let to internal, we build the dependency graph and
then use that to group definitions in mutually recursive blocks. Since
`x` has no edge, it was not being added to the dependency graph, so it
was not being translated to Internal, thus crashing later during
inference.
2023-09-26 13:17:50 +02:00
Łukasz Czajka
0cf993134e
Add fixity none and make aliases inherit fixity (#2391)
* Closes #2310 
* Makes aliases inherit fixity
* Adds `none` fixity definition to the standard library
2023-09-26 11:28:50 +02:00
Łukasz Czajka
019579bba2
Fix case formatting (#2387)
* Closes #2361 
* Aligns `case` and `let`
2023-09-26 10:11:46 +02:00
Łukasz Czajka
e509a6e16e
Instance holes (#2384)
* Closes #2383
2023-09-25 19:11:58 +02:00
Łukasz Czajka
a058487608
Support functions in instance parameters (#2385)
* Closes #2371
2023-09-25 13:08:55 +01:00
Paul Cadman
ea1fe1af3d
Avoid serialization of _packageFile field in juvix.yaml (#2381)
The _packageFile field of the Package record is used internally to track
the package file path and is used in error messages. It is not intended
to be present in the juvix.yaml file.

To express this the PackageFileType family with the Raw index is set to
`()`. However `()` is serialized to an empty array by Aeson, so the
`file: []` field was added to juvix.yaml.

NB: From aeson 2.2, fields with type `()` are ommitted when the
`omitNothingFields` flag is set to True, as it is for the package ToJSON
instance.

The solution in this PR is to set `PackageFileType 'Raw` to `Maybe ()`.
The
`omitNothingFields` flag then omits this field from the serialized
package object.


* Closes https://github.com/anoma/juvix/issues/2380
2023-09-21 19:51:31 +01:00
Paul Cadman
135a170b21
Do not call git fetch on git dependency if ref already exists in clone (#2379)
During path resolution, `git fetch` is called on every git dependency
clone. It's desirable to reduce the number of `git fetch` calls because
it makes a network call.

This PR changes the git dependency resolution to only call `git fetch`
if the existing clone does not already contain the specified ref.
2023-09-21 19:27:36 +02:00
Łukasz Czajka
fe90da58ed
Error for an instance subsumed by other instances (#2375)
* Closes #2372
2023-09-21 11:12:49 +01:00
Łukasz Czajka
c5d8641142
Error on local instances (#2376)
* Closes #2374

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-09-21 10:34:28 +01:00
Paul Cadman
6050b4061f
Bump version to 0.5.1 (#2370)
Juvix 0.5.1 is a bug fix release that contains just
https://github.com/anoma/juvix/pull/2368

- [x] Package version
- [x] Smoke test
- [x] Changelog
2023-09-15 13:31:23 +01:00
Łukasz Czajka
487fc58ba6
Fix bug in isTrait (#2368)
* Closes #2367
2023-09-14 17:50:38 +01:00
Paul Cadman
f84dcb4a50
Bump version to 0.5.0 and update CHANGELOG (#2366)
This PR updates:
- [x] Package version
- [x] Smoke test
- [x] Changelog
2023-09-14 12:41:54 +01:00
Jan Mas Rovira
8daca2ba0a
New fixity/iterator syntax (#2332)
- Closes #2330
- Closes #2329 

This pr implements the syntax changes described in #2330. It drops
support for the old yaml-based syntax.
Some valid examples:
```
syntax iterator for {init := 1; range := 1};

syntax fixity cons := binary {assoc := right};
syntax fixity cmp := binary;
syntax fixity cmp := binary {}; -- debatable whether we want to accept empty {} or not. I think we should
```
# Future work
This pr creates an asymmetry between iterators and operators
definitions. Iterators definition do not require a constructor. We could
add it to make it homogeneous, but it looks a bit redundant:
```
syntax iterator for := mkIterator {init := 1; range := 1};
```

We could consider merging iterator and fixity declarations with this
alternative syntax.
```
syntax XXX for := iterator {init := 1; range := 1};

syntax XXX cons := binary {assoc := right};
```
where `XXX` is a common keyword. Suggestion by @lukaszcz XXX = declare

---------

Co-authored-by: Łukasz Czajka <62751+lukaszcz@users.noreply.github.com>
Co-authored-by: Lukasz Czajka <lukasz@heliax.dev>
2023-09-14 10:57:38 +02:00
Łukasz Czajka
218e4d3484
Add newlines at end of JSON files (#2360)
* Closes #2349
2023-09-13 17:09:59 +02:00
Łukasz Czajka
95665283ac
Update the standard library to use the trait framework (#2359)
* Updates standard library to use traits
* Updates tests
2023-09-13 14:48:25 +02:00
Łukasz Czajka
fb3c897e9f
Fix instance import (#2350)
Fixes a bug which prevented some instances from being imported from
other modules.
2023-09-13 13:46:30 +02:00
Paul Cadman
c239d4a83d
Add new case syntax (#2353) 2023-09-13 11:58:08 +01:00
Paul Cadman
327cfaa0f6
Remove duplicated implicit pattern check from scoper (#2357)
This PR removes the CaseBranchImplicit error from the scoper. This error
is already handled in the arity/typechecker with a good error message:

 The arity checker error message for

```
   case b of {
      | {{true}} := false
```
is 

```
Expected an explicit pattern but found an implicit instance pattern: {{true}}
```

* Closes https://github.com/anoma/juvix/issues/2356
2023-09-13 12:16:05 +02:00
Łukasz Czajka
1710615fb0
VampIR range checks and error handling (#2344)
* Adds range checks and proper error handling to the Juvix-to-VampIR
pipeline.
* Adds the `--unsafe` option which disables the checks.
2023-09-12 19:56:28 +02:00
Jan Mas Rovira
73e2cf0fa8
Small refactor for traits (#2345)
This pr simplifies parsing by removing `FunctionParameterUnnamed`. It
also removes ghost wildcards introduced during parsing.

It also introduces an error for double braced atoms `{{x}}` that are not
on the left of an arrow `->`
2023-09-08 17:22:21 +02:00
Łukasz Czajka
08f123fa3d
Traits (#2320)
* Closes #1646 

Implements a basic trait framework. A simple instance search mechanism
is included which fails if there is more than one matching instance at
any step.

Example usage:
```
import Stdlib.Prelude open hiding {Show; mkShow; show};

trait
type Show A :=
  mkShow {
    show : A → String
  };

instance
showStringI : Show String := mkShow (show := id);

instance
showBoolI : Show Bool := mkShow (show := λ{x := if x "true" "false"});

instance
showNatI : Show Nat := mkShow (show := natToString);

showList {A} : {{Show A}} → List A → String
  | nil := "nil"
  | (h :: t) := Show.show h ++str " :: " ++str showList t;

instance
showListI {A} {{Show A}} : Show (List A) := mkShow (show := showList);

showMaybe {A} {{Show A}} : Maybe A → String
  | (just x) := "just (" ++str Show.show x ++str ")"
  | nothing := "nothing";

instance
showMaybeI {A} {{Show A}} : Show (Maybe A) := mkShow (show := showMaybe);

main : IO :=
  printStringLn (Show.show true) >>
  printStringLn (Show.show false) >>
  printStringLn (Show.show 3) >>
  printStringLn (Show.show [true; false]) >>
  printStringLn (Show.show [1; 2; 3]) >>
  printStringLn (Show.show [1; 2]) >>
  printStringLn (Show.show [true; false]) >>
  printStringLn (Show.show [just true; nothing; just false]) >>
  printStringLn (Show.show [just [1]; nothing; just [2; 3]]) >>
  printStringLn (Show.show "abba") >>
  printStringLn (Show.show ["a"; "b"; "c"; "d"]);
```

It is possible to manually provide an instance and to match on implicit
instances:
```
f {A} : {{Show A}} -> A -> String
  | {{mkShow s}} x -> s x;

f' {A} : {{Show A}} → A → String
  | {{M}} x := Show.show {{M}} x;
```

The trait parameters in instance types are checked to be structurally
decreasing to avoid looping in the instance search. So the following is
rejected:
```
type Box A := box A;

trait
type T A := mkT { pp : A → A };

instance
boxT {A} : {{T (Box A)}} → T (Box A) := mkT (λ{x := x});
```
We check whether each parameter is a strict subterm of some trait
parameter in the target. This ordering is included in the finite
multiset extension of the subterm ordering, hence terminating.
2023-09-08 12:16:43 +02:00
Jan Mas Rovira
36b390fcb0
Improve formatting of single-constructor types and records (#2342)
- Closes #2331.

The rules implemented in this pr are as follows.
1. If a type definition has only one constructor, no pipe is added. The
constructor is printed in the same line if it fits.
2. If a constructor is a record with a single field, the field is
printed in the same line if it fits. If the constructor has multiple
fields, they are printed aligned and indented after a line break.

Examples:
```
type T := constructT : T;

type T-wrapper := mkWrapper {unwrap : T};

type EnumRecord :=
  | --- doc for C1
    C1 {
      c1a : T;
      c1b : T
    }
  | C2 {
      c2a : T;
      c2b : T
    };
```
2023-09-07 16:20:14 +02:00