mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-13 08:47:17 +03:00
Merge branch 'testnet3' into testnet3
Signed-off-by: d0cd <23022326+d0cd@users.noreply.github.com>
This commit is contained in:
commit
e6d1a23402
@ -4,7 +4,7 @@ ls -la
|
||||
cd foo && ls -la
|
||||
|
||||
# Run `leo run`.
|
||||
$LEO run || exit
|
||||
$LEO run main 0u32 1u32 || exit
|
||||
|
||||
# Assert that the 'build' folder exists.
|
||||
if [ "$(ls -A build)" ]; then
|
||||
|
@ -4,11 +4,10 @@
|
||||
ls -la
|
||||
cd lottery && ls -la
|
||||
|
||||
# Run the play function.
|
||||
$LEO run play || exit
|
||||
|
||||
# Execute the play function.
|
||||
$LEO execute play || exit
|
||||
# Run the script.
|
||||
chmod +x ./run.sh || exit
|
||||
export -f leo
|
||||
./run.sh || exit
|
||||
)
|
||||
|
||||
(
|
||||
@ -17,14 +16,10 @@
|
||||
ls -la
|
||||
cd tictactoe && ls -la
|
||||
|
||||
# Create a new game.
|
||||
$LEO run new || exit
|
||||
|
||||
# Run the make_move function.
|
||||
$LEO run make_move || exit
|
||||
|
||||
# Execute the make_move function.
|
||||
$LEO execute make_move || exit
|
||||
# Run the script.
|
||||
chmod +x ./run.sh || exit
|
||||
export -f leo
|
||||
./run.sh || exit
|
||||
)
|
||||
|
||||
(
|
||||
@ -33,9 +28,8 @@
|
||||
ls -la
|
||||
cd token && ls -la
|
||||
|
||||
# Run the mint_public function.
|
||||
$LEO run mint_public || exit
|
||||
|
||||
# Execute the mint_public function.
|
||||
$LEO execute mint_public || exit
|
||||
# Run the script.
|
||||
chmod +x ./run.sh || exit
|
||||
export -f leo
|
||||
./run.sh || exit
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ do
|
||||
done
|
||||
|
||||
# Try to run `leo run`.
|
||||
$LEO run || exit
|
||||
$LEO run main 0u32 1u32 || exit
|
||||
|
||||
# Remove the dummy program.
|
||||
cd .. && rm -rf dummy
|
||||
|
5
.circleci/lottery/.gitignore
vendored
Normal file
5
.circleci/lottery/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
19
.circleci/lottery/README.md
Normal file
19
.circleci/lottery/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# lottery.aleo
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
leo run play
|
||||
|
||||
or
|
||||
|
||||
./run.sh
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute this program, run:
|
||||
```bash
|
||||
leo execute play
|
||||
```
|
26
.circleci/lottery/build/main.aleo
Normal file
26
.circleci/lottery/build/main.aleo
Normal file
@ -0,0 +1,26 @@
|
||||
program lottery.aleo;
|
||||
|
||||
record Ticket:
|
||||
owner as address.private;
|
||||
|
||||
|
||||
mapping num_winners:
|
||||
key as u8.public;
|
||||
value as u8.public;
|
||||
|
||||
function play:
|
||||
cast self.caller into r0 as Ticket.record;
|
||||
async play into r1;
|
||||
output r0 as Ticket.record;
|
||||
output r1 as lottery.aleo/play.future;
|
||||
|
||||
finalize play:
|
||||
lte block.height 1000u32 into r0;
|
||||
assert.eq r0 true;
|
||||
rand.chacha into r1 as boolean;
|
||||
assert.eq r1 true;
|
||||
get.or_use num_winners[0u8] 0u8 into r2;
|
||||
lt r2 5u8 into r3;
|
||||
assert.eq r3 true;
|
||||
add r2 1u8 into r4;
|
||||
set r4 into num_winners[0u8];
|
6
.circleci/lottery/build/program.json
Normal file
6
.circleci/lottery/build/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "lottery.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
1
.circleci/lottery/leo.lock
Normal file
1
.circleci/lottery/leo.lock
Normal file
@ -0,0 +1 @@
|
||||
package = []
|
6
.circleci/lottery/program.json
Normal file
6
.circleci/lottery/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "lottery.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
10
.circleci/lottery/run.sh
Normal file
10
.circleci/lottery/run.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
|
||||
# Run the lottery example
|
||||
leo run play || exit
|
30
.circleci/lottery/src/main.leo
Normal file
30
.circleci/lottery/src/main.leo
Normal file
@ -0,0 +1,30 @@
|
||||
// The 'lottery' program.
|
||||
program lottery.aleo {
|
||||
|
||||
mapping num_winners: u8 => u8;
|
||||
|
||||
record Ticket {
|
||||
owner: address,
|
||||
}
|
||||
|
||||
transition play() -> Ticket {
|
||||
let ticket: Ticket = Ticket {
|
||||
owner: self.caller,
|
||||
};
|
||||
return ticket then finalize();
|
||||
}
|
||||
|
||||
finalize play() {
|
||||
// Check that the lottery has not expired.
|
||||
assert(block.height <= 1000u32);
|
||||
|
||||
// Randomly select whether or not the ticket is a winner.
|
||||
assert(ChaCha::rand_bool());
|
||||
|
||||
// Check that the maximum number of winners have not been reached.
|
||||
let winners: u8 = num_winners.get_or_use(0u8, 0u8);
|
||||
assert(winners < 5u8);
|
||||
num_winners.set(0u8, winners + 1u8);
|
||||
|
||||
}
|
||||
}
|
@ -8,9 +8,6 @@ leo() {
|
||||
echo "Building and running the \`auction\` program..."
|
||||
(
|
||||
cd $EXAMPLES/auction || exit
|
||||
$LEO run place_bid || exit
|
||||
$LEO run resolve || exit
|
||||
$LEO run finish || exit
|
||||
|
||||
chmod +x $EXAMPLES/auction/run.sh || exit
|
||||
export -f leo || exit
|
||||
@ -27,9 +24,6 @@ fi
|
||||
echo "Building and running the \`basic_bank\` program..."
|
||||
(
|
||||
cd $EXAMPLES/basic_bank || exit
|
||||
$LEO run issue || exit
|
||||
$LEO run deposit || exit
|
||||
$LEO run withdraw || exit
|
||||
|
||||
chmod +x $EXAMPLES/basic_bank/run.sh || exit
|
||||
export -f leo || exit
|
||||
@ -63,7 +57,7 @@ fi
|
||||
echo "Building and running the \`bubblesort\` program..."
|
||||
(
|
||||
cd $EXAMPLES/bubblesort || exit
|
||||
$LEO run bubble_sort || exit
|
||||
$LEO run bubble_sort --file $EXAMPLES/bubblesort/inputs/bubblesort.in || exit
|
||||
)
|
||||
# Check that the bubblesort program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -76,7 +70,7 @@ fi
|
||||
echo "Building and running the \`core\` program..."
|
||||
(
|
||||
cd $EXAMPLES/core || exit
|
||||
$LEO run main || exit
|
||||
$LEO run main --file $EXAMPLES/core/inputs/core.in || exit
|
||||
)
|
||||
# Check that the core program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -89,7 +83,7 @@ fi
|
||||
echo "Building and running the \`groups\` program..."
|
||||
(
|
||||
cd $EXAMPLES/groups || exit
|
||||
$LEO run main || exit
|
||||
$LEO run main --file $EXAMPLES/groups/inputs/groups.in || exit
|
||||
)
|
||||
# Check that the groups program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -102,7 +96,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzdebruijn\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzdebruijn || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzdebruijn/inputs/ntzdebruijn.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzdebruijn program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -115,7 +109,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzgaudet\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzgaudet || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzgaudet/inputs/ntzgaudet.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzgaudet program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -128,7 +122,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzloops\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzloops || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzloops/inputs/ntzloops.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzloops program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -141,7 +135,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzmasks\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzmasks || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzmasks/inputs/ntzmasks.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzmasks program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -154,7 +148,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzreisers\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzreisers || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzreisers/inputs/ntzreisers.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzreisers program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -167,7 +161,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzseals\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzseals || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzseals/inputs/ntzseals.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzseals program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -180,7 +174,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzsearchtree\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzsearchtree || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzsearchtree/inputs/ntzsearchtree.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzsearchtree program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -193,7 +187,7 @@ fi
|
||||
echo "Building and running the \`hackers-delight/ntzsmallvals\` program..."
|
||||
(
|
||||
cd $EXAMPLES/hackers-delight/ntzsmallvals || exit
|
||||
$LEO run || exit
|
||||
$LEO run main --file $EXAMPLES/hackers-delight/ntzsmallvals/inputs/ntzsmallvals.in || exit
|
||||
)
|
||||
# Check that the hackers-delight/ntzsmallvals program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -206,7 +200,7 @@ fi
|
||||
echo "Building and running the \`helloworld\` program..."
|
||||
(
|
||||
cd $EXAMPLES/helloworld || exit
|
||||
$LEO run main || exit
|
||||
$LEO run main --file $EXAMPLES/helloworld/inputs/helloworld.in || exit
|
||||
)
|
||||
# Check that the helloworld program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -222,10 +216,10 @@ echo "Building and running the \`interest\` programs..."
|
||||
cd $EXAMPLES/interest || exit
|
||||
|
||||
# Run the fixed period interest program.
|
||||
$LEO run fixed_iteration_interest || exit
|
||||
$LEO run fixed_iteration_interest --file $EXAMPLES/interest/inputs/fixed.in || exit
|
||||
|
||||
# Run the bounded period interest program.
|
||||
$LEO run bounded_iteration_interest || exit
|
||||
$LEO run bounded_iteration_interest --file $EXAMPLES/interest/inputs/bounded.in || exit
|
||||
)
|
||||
# Check that the interest programs ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -238,7 +232,7 @@ fi
|
||||
echo "Building and running the \`message\` program..."
|
||||
(
|
||||
cd $EXAMPLES/message || exit
|
||||
$LEO run main || exit
|
||||
$LEO run main --file $EXAMPLES/message/inputs/message.in || exit
|
||||
)
|
||||
# Check that the message program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -252,7 +246,7 @@ echo "Building and running the \`tictactoe\` program..."
|
||||
(
|
||||
cd $EXAMPLES/tictactoe || exit
|
||||
$LEO run new || exit
|
||||
$LEO run make_move || exit
|
||||
$LEO run make_move --file $EXAMPLES/tictactoe/inputs/tictactoe.in || exit
|
||||
|
||||
chmod +x $EXAMPLES/tictactoe/run.sh || exit
|
||||
export -f leo
|
||||
@ -271,10 +265,10 @@ echo "Building and running the \`simple_token\` programs..."
|
||||
cd $EXAMPLES/simple_token || exit
|
||||
|
||||
# Run the mint program.
|
||||
$LEO run mint
|
||||
$LEO run mint --file $EXAMPLES/simple_token/inputs/mint.in || exit
|
||||
|
||||
# Run the transfer program.
|
||||
$LEO run transfer
|
||||
$LEO run transfer --file $EXAMPLES/simple_token/inputs/transfer.in || exit
|
||||
)
|
||||
# Check that the simple token programs ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -288,23 +282,9 @@ echo "Building and running the \`token\` program..."
|
||||
(
|
||||
cd $EXAMPLES/token || exit
|
||||
|
||||
# Run the mint_public function.
|
||||
$LEO run mint_public || exit
|
||||
|
||||
# Run the mint_private function.
|
||||
$LEO run mint_private || exit
|
||||
|
||||
# Run the transfer_public function.
|
||||
$LEO run transfer_public || exit
|
||||
|
||||
# Run the transfer_private function.
|
||||
$LEO run transfer_private || exit
|
||||
|
||||
# Run the transfer_private_to_public function.
|
||||
$LEO run transfer_private_to_public || exit
|
||||
|
||||
# Run the transfer_public_to_private function.
|
||||
$LEO run transfer_public_to_private || exit
|
||||
chmod +x $EXAMPLES/token/run.sh || exit
|
||||
export -f leo
|
||||
$EXAMPLES/token/run.sh || exit
|
||||
)
|
||||
# Check that the token program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -317,7 +297,7 @@ fi
|
||||
echo "Building and running the \`twoadicity\` program..."
|
||||
(
|
||||
cd $EXAMPLES/twoadicity || exit
|
||||
$LEO run main || exit
|
||||
$LEO run main --file $EXAMPLES/twoadicity/inputs/twoadicity.in || exit
|
||||
)
|
||||
# Check that the two-adicity program ran successfully.
|
||||
EXITCODE=$?
|
||||
@ -332,7 +312,7 @@ echo "Building and running the \`vote\` program..."
|
||||
cd $EXAMPLES/vote || exit
|
||||
|
||||
chmod +x $EXAMPLES/vote/run.sh || exit
|
||||
export -f leo
|
||||
export -f leo || exit
|
||||
$EXAMPLES/vote/run.sh || exit
|
||||
)
|
||||
# Check that the vote program ran successfully.
|
||||
@ -356,4 +336,4 @@ EXITCODE=$?
|
||||
if [ $EXITCODE -ne 0 ]; then
|
||||
echo "The \`lottery\` program failed to run successfully."
|
||||
exit $EXITCODE
|
||||
fi
|
||||
fi
|
||||
|
5
.circleci/tictactoe/.gitignore
vendored
Normal file
5
.circleci/tictactoe/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
82
.circleci/tictactoe/README.md
Normal file
82
.circleci/tictactoe/README.md
Normal file
@ -0,0 +1,82 @@
|
||||
<!-- # ⭕ Tic-Tac-Toe -->
|
||||
|
||||
[//]: # (<img alt="workshop/tictactoe" width="1412" src="../.resources/tictactoe.png">)
|
||||
|
||||
A standard game of Tic-Tac-Toe in Leo.
|
||||
|
||||
⭕ ❕ ⭕ ❕ ❌
|
||||
|
||||
➖ ➕ ➖ ➕ ➖
|
||||
|
||||
⭕ ❕ ❌ ❕ ⭕
|
||||
|
||||
➖ ➕ ➖ ➕ ➖
|
||||
|
||||
❌ ❕ ❌ ❕ ⭕
|
||||
|
||||
## Representing State
|
||||
Leo allows users to define composite data types with the `struct` keyword.
|
||||
The game board is represented by a struct called `Board`, which contains three `Row`s.
|
||||
An alternative representation would be to use an array, however, these are not yet supported in Leo.
|
||||
|
||||
## Language Features
|
||||
- `struct` declarations
|
||||
- conditional statements
|
||||
- early termination. Leo allows users to return from a function early using the `return` keyword.
|
||||
|
||||
## Running the Program
|
||||
|
||||
Leo provides users with a command line interface for compiling and running Leo programs.
|
||||
Users may either specify input values via the command line or provide an input file in `inputs/`.
|
||||
|
||||
### Providing inputs via the command line.
|
||||
1. Run
|
||||
```bash
|
||||
leo run <function_name> <input_1> <input_2> ...
|
||||
```
|
||||
See `./run.sh` for an example.
|
||||
|
||||
|
||||
### Using an input file.
|
||||
1. Modify `inputs/tictactoe.in` with the desired inputs.
|
||||
2. Run
|
||||
```bash
|
||||
leo run <function_name>
|
||||
```
|
||||
|
||||
## Executing the Program
|
||||
```bash
|
||||
leo execute <function_name> <input_1> <input_2> ...
|
||||
```
|
||||
|
||||
## Playing the Game
|
||||
|
||||
### 1. Create a new game board
|
||||
```bash
|
||||
leo run new
|
||||
```
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| 0 | 0 | 0 |
|
||||
| 0 | 0 | 0 |
|
||||
| 0 | 0 | 0 |
|
||||
|
||||
### 2. Player 1 makes a move
|
||||
```bash
|
||||
leo run make_move 1u8 1u8 1u8 "{ r1: { c1: 0u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }"
|
||||
```
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| 1 | 0 | 0 |
|
||||
| 0 | 0 | 0 |
|
||||
| 0 | 0 | 0 |
|
||||
|
||||
### 3. Player 2 makes a move
|
||||
```bash
|
||||
leo run make_move 2u8 2u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }"
|
||||
```
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| 1 | 0 | 0 |
|
||||
| 0 | 2 | 0 |
|
||||
| 0 | 0 | 0 |
|
237
.circleci/tictactoe/build/main.aleo
Normal file
237
.circleci/tictactoe/build/main.aleo
Normal file
@ -0,0 +1,237 @@
|
||||
program tictactoe.aleo;
|
||||
|
||||
struct Row:
|
||||
c1 as u8;
|
||||
c2 as u8;
|
||||
c3 as u8;
|
||||
|
||||
struct Board:
|
||||
r1 as Row;
|
||||
r2 as Row;
|
||||
r3 as Row;
|
||||
|
||||
|
||||
function new:
|
||||
cast 0u8 0u8 0u8 into r0 as Row;
|
||||
cast 0u8 0u8 0u8 into r1 as Row;
|
||||
cast 0u8 0u8 0u8 into r2 as Row;
|
||||
cast r0 r1 r2 into r3 as Board;
|
||||
output r3 as Board.private;
|
||||
|
||||
|
||||
closure check_for_win:
|
||||
input r0 as Board;
|
||||
input r1 as u8;
|
||||
is.eq r0.r1.c1 r1 into r2;
|
||||
is.eq r0.r1.c2 r1 into r3;
|
||||
and r2 r3 into r4;
|
||||
is.eq r0.r1.c3 r1 into r5;
|
||||
and r4 r5 into r6;
|
||||
is.eq r0.r2.c1 r1 into r7;
|
||||
is.eq r0.r2.c2 r1 into r8;
|
||||
and r7 r8 into r9;
|
||||
is.eq r0.r2.c3 r1 into r10;
|
||||
and r9 r10 into r11;
|
||||
or r6 r11 into r12;
|
||||
is.eq r0.r3.c1 r1 into r13;
|
||||
is.eq r0.r3.c3 r1 into r14;
|
||||
and r13 r14 into r15;
|
||||
is.eq r0.r3.c3 r1 into r16;
|
||||
and r15 r16 into r17;
|
||||
or r12 r17 into r18;
|
||||
is.eq r0.r1.c1 r1 into r19;
|
||||
is.eq r0.r2.c1 r1 into r20;
|
||||
and r19 r20 into r21;
|
||||
is.eq r0.r3.c1 r1 into r22;
|
||||
and r21 r22 into r23;
|
||||
or r18 r23 into r24;
|
||||
is.eq r0.r1.c2 r1 into r25;
|
||||
is.eq r0.r2.c3 r1 into r26;
|
||||
and r25 r26 into r27;
|
||||
is.eq r0.r3.c2 r1 into r28;
|
||||
and r27 r28 into r29;
|
||||
or r24 r29 into r30;
|
||||
is.eq r0.r1.c3 r1 into r31;
|
||||
is.eq r0.r2.c3 r1 into r32;
|
||||
and r31 r32 into r33;
|
||||
is.eq r0.r3.c3 r1 into r34;
|
||||
and r33 r34 into r35;
|
||||
or r30 r35 into r36;
|
||||
is.eq r0.r1.c1 r1 into r37;
|
||||
is.eq r0.r2.c2 r1 into r38;
|
||||
and r37 r38 into r39;
|
||||
is.eq r0.r3.c3 r1 into r40;
|
||||
and r39 r40 into r41;
|
||||
or r36 r41 into r42;
|
||||
is.eq r0.r1.c3 r1 into r43;
|
||||
is.eq r0.r2.c2 r1 into r44;
|
||||
and r43 r44 into r45;
|
||||
is.eq r0.r3.c1 r1 into r46;
|
||||
and r45 r46 into r47;
|
||||
or r42 r47 into r48;
|
||||
output r48 as boolean;
|
||||
|
||||
|
||||
function make_move:
|
||||
input r0 as u8.private;
|
||||
input r1 as u8.private;
|
||||
input r2 as u8.private;
|
||||
input r3 as Board.private;
|
||||
is.eq r0 1u8 into r4;
|
||||
is.eq r0 2u8 into r5;
|
||||
or r4 r5 into r6;
|
||||
assert.eq r6 true;
|
||||
lte 1u8 r1 into r7;
|
||||
lte r1 3u8 into r8;
|
||||
and r7 r8 into r9;
|
||||
assert.eq r9 true;
|
||||
lte 1u8 r2 into r10;
|
||||
lte r2 3u8 into r11;
|
||||
and r10 r11 into r12;
|
||||
assert.eq r12 true;
|
||||
is.eq r1 1u8 into r13;
|
||||
is.eq r2 1u8 into r14;
|
||||
and r13 r14 into r15;
|
||||
is.eq r3.r1.c1 0u8 into r16;
|
||||
and r15 r16 into r17;
|
||||
is.eq r1 1u8 into r18;
|
||||
is.eq r2 2u8 into r19;
|
||||
and r18 r19 into r20;
|
||||
is.eq r3.r1.c2 0u8 into r21;
|
||||
and r20 r21 into r22;
|
||||
is.eq r1 1u8 into r23;
|
||||
is.eq r2 3u8 into r24;
|
||||
and r23 r24 into r25;
|
||||
is.eq r3.r1.c3 0u8 into r26;
|
||||
and r25 r26 into r27;
|
||||
is.eq r1 2u8 into r28;
|
||||
is.eq r2 1u8 into r29;
|
||||
and r28 r29 into r30;
|
||||
is.eq r3.r2.c1 0u8 into r31;
|
||||
and r30 r31 into r32;
|
||||
is.eq r1 2u8 into r33;
|
||||
is.eq r2 2u8 into r34;
|
||||
and r33 r34 into r35;
|
||||
is.eq r3.r2.c2 0u8 into r36;
|
||||
and r35 r36 into r37;
|
||||
is.eq r1 2u8 into r38;
|
||||
is.eq r2 3u8 into r39;
|
||||
and r38 r39 into r40;
|
||||
is.eq r3.r2.c3 0u8 into r41;
|
||||
and r40 r41 into r42;
|
||||
is.eq r1 3u8 into r43;
|
||||
is.eq r2 1u8 into r44;
|
||||
and r43 r44 into r45;
|
||||
is.eq r3.r3.c1 0u8 into r46;
|
||||
and r45 r46 into r47;
|
||||
is.eq r1 3u8 into r48;
|
||||
is.eq r2 2u8 into r49;
|
||||
and r48 r49 into r50;
|
||||
is.eq r3.r3.c2 0u8 into r51;
|
||||
and r50 r51 into r52;
|
||||
is.eq r1 3u8 into r53;
|
||||
is.eq r2 3u8 into r54;
|
||||
and r53 r54 into r55;
|
||||
is.eq r3.r3.c3 0u8 into r56;
|
||||
and r55 r56 into r57;
|
||||
ternary r57 r0 r3.r3.c3 into r58;
|
||||
ternary r52 r0 r3.r3.c2 into r59;
|
||||
ternary r52 r3.r3.c3 r58 into r60;
|
||||
ternary r47 r0 r3.r3.c1 into r61;
|
||||
ternary r47 r3.r3.c2 r59 into r62;
|
||||
ternary r47 r3.r3.c3 r60 into r63;
|
||||
ternary r42 r0 r3.r2.c3 into r64;
|
||||
ternary r42 r3.r3.c1 r61 into r65;
|
||||
ternary r42 r3.r3.c2 r62 into r66;
|
||||
ternary r42 r3.r3.c3 r63 into r67;
|
||||
ternary r37 r0 r3.r2.c2 into r68;
|
||||
ternary r37 r3.r2.c3 r64 into r69;
|
||||
ternary r37 r3.r3.c1 r65 into r70;
|
||||
ternary r37 r3.r3.c2 r66 into r71;
|
||||
ternary r37 r3.r3.c3 r67 into r72;
|
||||
ternary r32 r0 r3.r2.c1 into r73;
|
||||
ternary r32 r3.r2.c2 r68 into r74;
|
||||
ternary r32 r3.r2.c3 r69 into r75;
|
||||
ternary r32 r3.r3.c1 r70 into r76;
|
||||
ternary r32 r3.r3.c2 r71 into r77;
|
||||
ternary r32 r3.r3.c3 r72 into r78;
|
||||
ternary r27 r0 r3.r1.c3 into r79;
|
||||
ternary r27 r3.r2.c1 r73 into r80;
|
||||
ternary r27 r3.r2.c2 r74 into r81;
|
||||
ternary r27 r3.r2.c3 r75 into r82;
|
||||
ternary r27 r3.r3.c1 r76 into r83;
|
||||
ternary r27 r3.r3.c2 r77 into r84;
|
||||
ternary r27 r3.r3.c3 r78 into r85;
|
||||
ternary r22 r0 r3.r1.c2 into r86;
|
||||
ternary r22 r3.r1.c3 r79 into r87;
|
||||
ternary r22 r3.r2.c1 r80 into r88;
|
||||
ternary r22 r3.r2.c2 r81 into r89;
|
||||
ternary r22 r3.r2.c3 r82 into r90;
|
||||
ternary r22 r3.r3.c1 r83 into r91;
|
||||
ternary r22 r3.r3.c2 r84 into r92;
|
||||
ternary r22 r3.r3.c3 r85 into r93;
|
||||
ternary r17 r0 r3.r1.c1 into r94;
|
||||
ternary r17 r3.r1.c2 r86 into r95;
|
||||
ternary r17 r3.r1.c3 r87 into r96;
|
||||
ternary r17 r3.r2.c1 r88 into r97;
|
||||
ternary r17 r3.r2.c2 r89 into r98;
|
||||
ternary r17 r3.r2.c3 r90 into r99;
|
||||
ternary r17 r3.r3.c1 r91 into r100;
|
||||
ternary r17 r3.r3.c2 r92 into r101;
|
||||
ternary r17 r3.r3.c3 r93 into r102;
|
||||
cast r94 r95 r96 into r103 as Row;
|
||||
cast r97 r98 r99 into r104 as Row;
|
||||
cast r100 r101 r102 into r105 as Row;
|
||||
cast r103 r104 r105 into r106 as Board;
|
||||
call check_for_win r106 1u8 into r107;
|
||||
call check_for_win r106 2u8 into r108;
|
||||
not r107 into r109;
|
||||
and r109 r108 into r110;
|
||||
ternary r110 r106.r1.c1 r106.r1.c1 into r111;
|
||||
not r107 into r112;
|
||||
and r112 r108 into r113;
|
||||
ternary r113 r106.r1.c2 r106.r1.c2 into r114;
|
||||
not r107 into r115;
|
||||
and r115 r108 into r116;
|
||||
ternary r116 r106.r1.c3 r106.r1.c3 into r117;
|
||||
cast r111 r114 r117 into r118 as Row;
|
||||
not r107 into r119;
|
||||
and r119 r108 into r120;
|
||||
ternary r120 r106.r2.c1 r106.r2.c1 into r121;
|
||||
not r107 into r122;
|
||||
and r122 r108 into r123;
|
||||
ternary r123 r106.r2.c2 r106.r2.c2 into r124;
|
||||
not r107 into r125;
|
||||
and r125 r108 into r126;
|
||||
ternary r126 r106.r2.c3 r106.r2.c3 into r127;
|
||||
cast r121 r124 r127 into r128 as Row;
|
||||
not r107 into r129;
|
||||
and r129 r108 into r130;
|
||||
ternary r130 r106.r3.c1 r106.r3.c1 into r131;
|
||||
not r107 into r132;
|
||||
and r132 r108 into r133;
|
||||
ternary r133 r106.r3.c2 r106.r3.c2 into r134;
|
||||
not r107 into r135;
|
||||
and r135 r108 into r136;
|
||||
ternary r136 r106.r3.c3 r106.r3.c3 into r137;
|
||||
cast r131 r134 r137 into r138 as Row;
|
||||
cast r118 r128 r138 into r139 as Board;
|
||||
not r107 into r140;
|
||||
and r140 r108 into r141;
|
||||
ternary r141 2u8 0u8 into r142;
|
||||
ternary r107 r106.r1.c1 r139.r1.c1 into r143;
|
||||
ternary r107 r106.r1.c2 r139.r1.c2 into r144;
|
||||
ternary r107 r106.r1.c3 r139.r1.c3 into r145;
|
||||
cast r143 r144 r145 into r146 as Row;
|
||||
ternary r107 r106.r2.c1 r139.r2.c1 into r147;
|
||||
ternary r107 r106.r2.c2 r139.r2.c2 into r148;
|
||||
ternary r107 r106.r2.c3 r139.r2.c3 into r149;
|
||||
cast r147 r148 r149 into r150 as Row;
|
||||
ternary r107 r106.r3.c1 r139.r3.c1 into r151;
|
||||
ternary r107 r106.r3.c2 r139.r3.c2 into r152;
|
||||
ternary r107 r106.r3.c3 r139.r3.c3 into r153;
|
||||
cast r151 r152 r153 into r154 as Row;
|
||||
cast r146 r150 r154 into r155 as Board;
|
||||
ternary r107 1u8 r142 into r156;
|
||||
output r155 as Board.private;
|
||||
output r156 as u8.private;
|
6
.circleci/tictactoe/build/program.json
Normal file
6
.circleci/tictactoe/build/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "tictactoe.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
18
.circleci/tictactoe/inputs/tictactoe.in
Normal file
18
.circleci/tictactoe/inputs/tictactoe.in
Normal file
@ -0,0 +1,18 @@
|
||||
// The `new` function does not take any inputs.
|
||||
[new]
|
||||
|
||||
// Inputs for the `make_move` function.
|
||||
// - `player` : A u8 representing the player making the move. 1 for player 1, 2 for player 2.
|
||||
// - `row` : A u8 representing the row to make the move in.
|
||||
// - `column` : A u8 representing the column to make the move in.
|
||||
// - `board` : A representation of the board state.
|
||||
[make_move]
|
||||
player: u8 = 1u8;
|
||||
row: u8 = 1u8;
|
||||
col: u8 = 1u8;
|
||||
board: Board = Board {
|
||||
r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
};
|
||||
|
1
.circleci/tictactoe/leo.lock
Normal file
1
.circleci/tictactoe/leo.lock
Normal file
@ -0,0 +1 @@
|
||||
package = []
|
6
.circleci/tictactoe/program.json
Normal file
6
.circleci/tictactoe/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "tictactoe.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
157
.circleci/tictactoe/run.sh
Normal file
157
.circleci/tictactoe/run.sh
Normal file
@ -0,0 +1,157 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
# Create a new game.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 0: Creating a new game of Tic-Tac-Toe ########
|
||||
######## ########
|
||||
######## | | | | ########
|
||||
######## | | | | ########
|
||||
######## | | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run new || exit
|
||||
|
||||
# Have the Player 1 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 1: Player 1 makes the 1st move. ########
|
||||
######## ########
|
||||
######## | x | | | ########
|
||||
######## | | | | ########
|
||||
######## | | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 1u8 1u8 1u8 "{ r1: { c1: 0u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 2 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 2: Player 2 makes the 2nd move. ########
|
||||
######## ########
|
||||
######## | x | | | ########
|
||||
######## | | o | | ########
|
||||
######## | | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 2u8 2u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 1 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 3: Player 1 makes the 3rd move. ########
|
||||
######## ########
|
||||
######## | x | | | ########
|
||||
######## | | o | | ########
|
||||
######## | x | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 1u8 3u8 1u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 2u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 2 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 4: Player 2 makes the 4th move. ########
|
||||
######## ########
|
||||
######## | x | | | ########
|
||||
######## | o | o | | ########
|
||||
######## | x | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 2u8 2u8 1u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 2u8, c3: 0u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 1 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 5: Player 1 makes the 5th move. ########
|
||||
######## ########
|
||||
######## | x | | | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 1u8 2u8 3u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 0u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 2 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 6: Player 2 makes the 6th move. ########
|
||||
######## ########
|
||||
######## | x | o | | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 2u8 1u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 1 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 7: Player 1 makes the 7th move. ########
|
||||
######## ########
|
||||
######## | x | o | | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | x | | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 1u8 3u8 2u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit
|
||||
|
||||
# Have the Player 2 make a move.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 8: Player 2 makes the 8th move. ########
|
||||
######## ########
|
||||
######## | x | o | | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | x | o | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 2u8 3u8 3u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 1u8, c3: 0u8 } }" || exit
|
||||
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 9: Player 1 makes the 9th move. ########
|
||||
######## ########
|
||||
######## | x | o | x | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | x | o | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run make_move 1u8 1u8 3u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 1u8, c3: 2u8 } }" || exit
|
||||
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## Game Complete! Players 1 & 2 Tied ########
|
||||
######## ########
|
||||
######## | x | o | x | ########
|
||||
######## | o | o | x | ########
|
||||
######## | x | x | o | ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
111
.circleci/tictactoe/src/main.leo
Normal file
111
.circleci/tictactoe/src/main.leo
Normal file
@ -0,0 +1,111 @@
|
||||
program tictactoe.aleo {
|
||||
// A row in a tic tac toe board.
|
||||
// - `c1` : The first entry in the row.
|
||||
// - `c2` : The second entry in the row.
|
||||
// - `c3` : The third entry in the row.
|
||||
// A valid entry is either 0, 1, or 2, where 0 is empty, 1 corresponds to player 1, and 2 corresponds to player 2.
|
||||
// Any other values are invalid.
|
||||
struct Row {
|
||||
c1: u8,
|
||||
c2: u8,
|
||||
c3: u8
|
||||
}
|
||||
|
||||
// A tic tac toe board.
|
||||
// - `r1` : The first row in the board.
|
||||
// - `r2` : The second row in the board.
|
||||
// - `r3` : The third row in the board.
|
||||
struct Board {
|
||||
r1: Row,
|
||||
r2: Row,
|
||||
r3: Row,
|
||||
}
|
||||
|
||||
// Returns an empty board.
|
||||
transition new() -> Board {
|
||||
return Board {
|
||||
r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 },
|
||||
};
|
||||
}
|
||||
|
||||
// Returns `true` if there exists a row, column, or diagonal with all entries occupied by the same player.
|
||||
// - `b` : A tic tac toe board.
|
||||
// - `p` : A number corresponding to a player.
|
||||
function check_for_win(b: Board, p: u8) -> bool {
|
||||
return
|
||||
(b.r1.c1 == p && b.r1.c2 == p && b.r1.c3 == p) || // row 1
|
||||
(b.r2.c1 == p && b.r2.c2 == p && b.r2.c3 == p) || // row 2
|
||||
(b.r3.c1 == p && b.r3.c3 == p && b.r3.c3 == p) || // row 3
|
||||
(b.r1.c1 == p && b.r2.c1 == p && b.r3.c1 == p) || // column 1
|
||||
(b.r1.c2 == p && b.r2.c3 == p && b.r3.c2 == p) || // column 2
|
||||
(b.r1.c3 == p && b.r2.c3 == p && b.r3.c3 == p) || // column 3
|
||||
(b.r1.c1 == p && b.r2.c2 == p && b.r3.c3 == p) || // diagonal
|
||||
(b.r1.c3 == p && b.r2.c2 == p && b.r3.c1 == p); // other diagonal
|
||||
}
|
||||
|
||||
// Returns an updated tic tac toe board with a move made by a player.
|
||||
// Returns a `u8` corresponding to the player who won the game, or 0 if no one has won yet.
|
||||
// - `player` : A number corresponding to a player.
|
||||
// - `row` : The row of the move.
|
||||
// - `col` : The column of the move.
|
||||
// - `board` : A tic tac toe board.
|
||||
// Assumes that `player` is either 1 or 2.
|
||||
// Assumes that `row` and `col` are valid indices into the board.
|
||||
// If an entry is already occupied, the move is invalid and the board is returned unchanged.
|
||||
transition make_move(player: u8, row: u8, col: u8, board: Board) -> (Board, u8) {
|
||||
// Check that inputs are valid.
|
||||
assert(player == 1u8 || player == 2u8);
|
||||
assert(1u8 <= row && row <= 3u8);
|
||||
assert(1u8 <= col && col <= 3u8);
|
||||
|
||||
// Unpack the entries in the board into variables.
|
||||
let r1c1: u8 = board.r1.c1;
|
||||
let r1c2: u8 = board.r1.c2;
|
||||
let r1c3: u8 = board.r1.c3;
|
||||
let r2c1: u8 = board.r2.c1;
|
||||
let r2c2: u8 = board.r2.c2;
|
||||
let r2c3: u8 = board.r2.c3;
|
||||
let r3c1: u8 = board.r3.c1;
|
||||
let r3c2: u8 = board.r3.c2;
|
||||
let r3c3: u8 = board.r3.c3;
|
||||
|
||||
// Update the appropriate entry with the given move.
|
||||
if row == 1u8 && col == 1u8 && r1c1 == 0u8 {
|
||||
r1c1 = player;
|
||||
} else if row == 1u8 && col == 2u8 && r1c2 == 0u8 {
|
||||
r1c2 = player;
|
||||
} else if row == 1u8 && col == 3u8 && r1c3 == 0u8 {
|
||||
r1c3 = player;
|
||||
} else if row == 2u8 && col == 1u8 && r2c1 == 0u8 {
|
||||
r2c1 = player;
|
||||
} else if row == 2u8 && col == 2u8 && r2c2 == 0u8 {
|
||||
r2c2 = player;
|
||||
} else if row == 2u8 && col == 3u8 && r2c3 == 0u8 {
|
||||
r2c3 = player;
|
||||
} else if row == 3u8 && col == 1u8 && r3c1 == 0u8 {
|
||||
r3c1 = player;
|
||||
} else if row == 3u8 && col == 2u8 && r3c2 == 0u8 {
|
||||
r3c2 = player;
|
||||
} else if row == 3u8 && col == 3u8 && r3c3 == 0u8 {
|
||||
r3c3 = player;
|
||||
}
|
||||
|
||||
// Construct the updated game board.
|
||||
let updated: Board = Board {
|
||||
r1: Row { c1: r1c1, c2: r1c2, c3: r1c3 },
|
||||
r2: Row { c1: r2c1, c2: r2c2, c3: r2c3 },
|
||||
r3: Row { c1: r3c1, c2: r3c2, c3: r3c3 },
|
||||
};
|
||||
|
||||
// Check if the game is over.
|
||||
if check_for_win(updated, 1u8) {
|
||||
return (updated, 1u8);
|
||||
} else if check_for_win(updated, 2u8) {
|
||||
return (updated, 2u8);
|
||||
} else {
|
||||
return (updated, 0u8);
|
||||
}
|
||||
}
|
||||
}
|
5
.circleci/token/.gitignore
vendored
Normal file
5
.circleci/token/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
12
.circleci/token/README.md
Normal file
12
.circleci/token/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
<!-- # 🪙 Token -->
|
||||
|
||||
[//]: # (<img alt="workshop/token" width="1412" src="../.resources/token.png">)
|
||||
|
||||
A transparent & shielded custom token in Leo.
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
93
.circleci/token/build/main.aleo
Normal file
93
.circleci/token/build/main.aleo
Normal file
@ -0,0 +1,93 @@
|
||||
program token.aleo;
|
||||
|
||||
record token:
|
||||
owner as address.private;
|
||||
amount as u64.private;
|
||||
|
||||
|
||||
mapping account:
|
||||
key as address.public;
|
||||
value as u64.public;
|
||||
|
||||
function mint_public:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
async mint_public r0 r1 into r2;
|
||||
output r2 as token.aleo/mint_public.future;
|
||||
|
||||
finalize mint_public:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
add r2 r1 into r3;
|
||||
set r3 into account[r0];
|
||||
|
||||
|
||||
function mint_private:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.private;
|
||||
cast r0 r1 into r2 as token.record;
|
||||
output r2 as token.record;
|
||||
|
||||
|
||||
function transfer_public:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
async transfer_public self.caller r0 r1 into r2;
|
||||
output r2 as token.aleo/transfer_public.future;
|
||||
|
||||
finalize transfer_public:
|
||||
input r0 as address.public;
|
||||
input r1 as address.public;
|
||||
input r2 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r3;
|
||||
sub r3 r2 into r4;
|
||||
set r4 into account[r0];
|
||||
get.or_use account[r1] 0u64 into r5;
|
||||
add r5 r2 into r6;
|
||||
set r6 into account[r1];
|
||||
|
||||
|
||||
function transfer_private:
|
||||
input r0 as token.record;
|
||||
input r1 as address.private;
|
||||
input r2 as u64.private;
|
||||
sub r0.amount r2 into r3;
|
||||
cast r0.owner r3 into r4 as token.record;
|
||||
cast r1 r2 into r5 as token.record;
|
||||
output r4 as token.record;
|
||||
output r5 as token.record;
|
||||
|
||||
|
||||
function transfer_private_to_public:
|
||||
input r0 as token.record;
|
||||
input r1 as address.public;
|
||||
input r2 as u64.public;
|
||||
sub r0.amount r2 into r3;
|
||||
cast r0.owner r3 into r4 as token.record;
|
||||
async transfer_private_to_public r1 r2 into r5;
|
||||
output r4 as token.record;
|
||||
output r5 as token.aleo/transfer_private_to_public.future;
|
||||
|
||||
finalize transfer_private_to_public:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
add r2 r1 into r3;
|
||||
set r3 into account[r0];
|
||||
|
||||
|
||||
function transfer_public_to_private:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
cast r0 r1 into r2 as token.record;
|
||||
async transfer_public_to_private self.caller r1 into r3;
|
||||
output r2 as token.record;
|
||||
output r3 as token.aleo/transfer_public_to_private.future;
|
||||
|
||||
finalize transfer_public_to_private:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
sub r2 r1 into r3;
|
||||
set r3 into account[r0];
|
6
.circleci/token/build/program.json
Normal file
6
.circleci/token/build/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "token.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
1
.circleci/token/leo.lock
Normal file
1
.circleci/token/leo.lock
Normal file
@ -0,0 +1 @@
|
||||
package = []
|
6
.circleci/token/program.json
Normal file
6
.circleci/token/program.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": "token.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
239
.circleci/token/run.sh
Normal file
239
.circleci/token/run.sh
Normal file
@ -0,0 +1,239 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
|
||||
# The private key and address of Alice.
|
||||
# Swap these into program.json, when running transactions as the first bidder.
|
||||
# "private_key": "APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR",
|
||||
# "address": "aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q"
|
||||
|
||||
# The private key and address of Bob.
|
||||
# Swap these into program.json, when running transactions as the second bidder.
|
||||
# "private_key": "APrivateKey1zkpFo72g7N9iFt3JzzeG8CqsS5doAiXyFvNCgk2oHvjRCzF"
|
||||
# "address": "aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z"
|
||||
|
||||
# Swap in the private key of Alice.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
|
||||
" > .env
|
||||
|
||||
# Publicly mint 100 tokens for Alice.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 1: Publicly mint 100 tokens for Alice ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run mint_public aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q 100u64
|
||||
|
||||
# Swap in the private key of Bob.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkpFo72g7N9iFt3JzzeG8CqsS5doAiXyFvNCgk2oHvjRCzF
|
||||
" > .env
|
||||
|
||||
# Privately mint 100 tokens for Bob.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 2: Privately mint 100 tokens for Bob ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run mint_private aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z 100u64
|
||||
|
||||
# Swap in the private key of Alice.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
|
||||
" > .env
|
||||
|
||||
# Publicly transfer 10 tokens from Alice to Bob.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 3: Publicly transfer 10 tokens from Alice to Bob ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 90 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 10 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run transfer_public aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z 10u64
|
||||
|
||||
# Swap in the private key of Bob.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkpFo72g7N9iFt3JzzeG8CqsS5doAiXyFvNCgk2oHvjRCzF
|
||||
" > .env
|
||||
|
||||
# Privately transfer 20 tokens from Bob to Alice.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 4: Privately transfer 20 tokens from Bob to Alice ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 90 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 10 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 20 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 80 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run transfer_private "{
|
||||
owner: aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z.private,
|
||||
amount: 100u64.private,
|
||||
_nonce: 6586771265379155927089644749305420610382723873232320906747954786091923851913group.public
|
||||
}" aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q 20u64
|
||||
|
||||
# Swap in the private key of Alice.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
|
||||
" > .env
|
||||
|
||||
# Convert 30 public tokens from Alice into 30 private tokens for Bob.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 5: Convert 30 public tokens from Alice into 30 ########
|
||||
######## private tokens for Bob. ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 60 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 10 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 20 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 110 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run transfer_public_to_private aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z 30u64
|
||||
|
||||
# Swap in the private key of Bob.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkpFo72g7N9iFt3JzzeG8CqsS5doAiXyFvNCgk2oHvjRCzF
|
||||
" > .env
|
||||
|
||||
# Convert 40 private tokens from Bob into 40 public tokens for Alice.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 6: Convert 40 private tokens from Bob into 40 ########
|
||||
######## public tokens for Alice. ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PUBLIC BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 10 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | PRIVATE BALANCES | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Alice | 20 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Bob | 70 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run transfer_private_to_public "{
|
||||
owner: aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z.private,
|
||||
amount: 80u64.private,
|
||||
_nonce: 1852830456042139988098466781381363679605019151318121788109768539956661608520group.public
|
||||
}" aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q 40u64
|
||||
|
||||
|
||||
# Swap in the private key of Alice.
|
||||
# This is done to ensure that program.json is the same after every execution of ./run.sh.
|
||||
echo "
|
||||
NETWORK=testnet3
|
||||
PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
|
||||
" > .env
|
128
.circleci/token/src/main.leo
Normal file
128
.circleci/token/src/main.leo
Normal file
@ -0,0 +1,128 @@
|
||||
program token.aleo {
|
||||
// On-chain storage of an `account` map, with `address` as the key,
|
||||
// and `u64` as the value.
|
||||
mapping account: address => u64;
|
||||
|
||||
record token {
|
||||
// The token owner.
|
||||
owner: address,
|
||||
// The token amount.
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
/* Mint */
|
||||
|
||||
// The function `mint_public` issues the specified token amount for the token receiver publicly on the network.
|
||||
transition mint_public(public receiver: address, public amount: u64) {
|
||||
// Mint the tokens publicly by invoking the computation on-chain.
|
||||
return then finalize(receiver, amount);
|
||||
}
|
||||
|
||||
finalize mint_public(public receiver: address, public amount: u64) {
|
||||
// Increments `account[receiver]` by `amount`.
|
||||
// If `account[receiver]` does not exist, it will be created.
|
||||
// If `account[receiver] + amount` overflows, `mint_public` is reverted.
|
||||
let current_amount: u64 = Mapping::get_or_use(account, receiver, 0u64);
|
||||
Mapping::set(account, receiver, current_amount + amount);
|
||||
}
|
||||
|
||||
// The function `mint_private` initializes a new record with the specified amount of tokens for the receiver.
|
||||
transition mint_private(receiver: address, amount: u64) -> token {
|
||||
return token {
|
||||
owner: receiver,
|
||||
amount: amount,
|
||||
};
|
||||
}
|
||||
|
||||
/* Transfer */
|
||||
transition transfer_public(public receiver: address, public amount: u64) {
|
||||
// Transfer the tokens publicly, by invoking the computation on-chain.
|
||||
return then finalize(self.caller, receiver, amount);
|
||||
}
|
||||
|
||||
finalize transfer_public(public sender: address, public receiver: address, public amount: u64) {
|
||||
// Decrements `account[sender]` by `amount`.
|
||||
// If `account[sender]` does not exist, it will be created.
|
||||
// If `account[sender] - amount` underflows, `transfer_public` is reverted.
|
||||
let sender_amount: u64 = Mapping::get_or_use(account, sender, 0u64);
|
||||
Mapping::set(account, sender, sender_amount - amount);
|
||||
// Increments `account[receiver]` by `amount`.
|
||||
// If `account[receiver]` does not exist, it will be created.
|
||||
// If `account[receiver] + amount` overflows, `transfer_public` is reverted.
|
||||
let receiver_amount: u64 = Mapping::get_or_use(account, receiver, 0u64);
|
||||
Mapping::set(account, receiver, receiver_amount + amount);
|
||||
}
|
||||
|
||||
// The function `transfer_private` sends the specified token amount to the token receiver from the specified token record.
|
||||
transition transfer_private(sender: token, receiver: address, amount: u64) -> (token, token) {
|
||||
// Checks the given token record has sufficient balance.
|
||||
// This `sub` operation is safe, and the proof will fail if an overflow occurs.
|
||||
// `difference` holds the change amount to be returned to sender.
|
||||
let difference: u64 = sender.amount - amount;
|
||||
|
||||
// Produce a token record with the change amount for the sender.
|
||||
let remaining: token = token {
|
||||
owner: sender.owner,
|
||||
amount: difference,
|
||||
};
|
||||
|
||||
// Produce a token record for the specified receiver.
|
||||
let transferred: token = token {
|
||||
owner: receiver,
|
||||
amount: amount,
|
||||
};
|
||||
|
||||
// Output the sender's change record and the receiver's record.
|
||||
return (remaining, transferred);
|
||||
}
|
||||
|
||||
// The function `transfer_private_to_public` turns a specified token amount from a token record into public tokens for the specified receiver.
|
||||
// This function preserves privacy for the sender's record, however it publicly reveals the token receiver and the token amount.
|
||||
transition transfer_private_to_public(sender: token, public receiver: address, public amount: u64) -> token {
|
||||
// Checks the given token record has a sufficient token amount.
|
||||
// This `sub` operation is safe, and the proof will fail if an underflow occurs.
|
||||
// `difference` holds the change amount for the caller.
|
||||
let difference: u64 = sender.amount - amount;
|
||||
|
||||
// Produces a token record with the change amount for the caller.
|
||||
let remaining: token = token {
|
||||
owner: sender.owner,
|
||||
amount: difference,
|
||||
};
|
||||
|
||||
// Output the sender's change record.
|
||||
// Increment the token amount publicly for the token receiver.
|
||||
return remaining then finalize(receiver, amount);
|
||||
}
|
||||
|
||||
finalize transfer_private_to_public(public receiver: address, public amount: u64) {
|
||||
// Increments `account[receiver]` by `amount`.
|
||||
// If `account[receiver]` does not exist, it will be created.
|
||||
// If `account[receiver] + amount` overflows, `transfer_private_to_public` is reverted.
|
||||
let current_amount: u64 = Mapping::get_or_use(account, receiver, 0u64);
|
||||
Mapping::set(account, receiver, current_amount + amount);
|
||||
}
|
||||
|
||||
// The function `transfer_public_to_private` turns a specified token amount from `account` into a token record for the specified receiver.
|
||||
// This function preserves privacy for the receiver's record, however it publicly reveals the caller and the specified token amount.
|
||||
transition transfer_public_to_private(public receiver: address, public amount: u64) -> token {
|
||||
// Produces a token record for the token receiver.
|
||||
let transferred: token = token {
|
||||
owner: receiver,
|
||||
amount: amount,
|
||||
};
|
||||
|
||||
// Output the receiver's record.
|
||||
// Decrement the token amount of the caller publicly.
|
||||
return transferred then finalize(self.caller, amount);
|
||||
}
|
||||
|
||||
finalize transfer_public_to_private(public sender: address, public amount: u64) {
|
||||
// Decrements `account[sender]` by `amount`.
|
||||
// If `account[sender]` does not exist, it will be created.
|
||||
// If `account[sender] - amount` underflows, `transfer_public_to_private` is reverted.
|
||||
let current_amount: u64 = Mapping::get_or_use(account, sender, 0u64);
|
||||
Mapping::set(account, sender, current_amount - amount);
|
||||
}
|
||||
|
||||
}
|
@ -64,7 +64,7 @@ Leo is a big project, so (non-)adherence to best practices related to performanc
|
||||
### Memory handling
|
||||
- If the final size is known, pre-allocate the collections (`Vec`, `HashMap` etc.) using `with_capacity` or `reserve` - this ensures that there are both fewer allocations (which involve system calls) and that the final allocated capacity is as close to the required size as possible.
|
||||
- Create the collections right before they are populated/used, as opposed to e.g. creating a few big ones at the beginning of a function and only using them later on; this reduces the amount of time they occupy memory.
|
||||
- If an intermediate vector is avoidable, use an `Iterator` instead; most of the time this just amounts to omitting the call to `.collect()` if a single-pass iteraton follows afterwards, or returning an `impl Iterator<Item = T>` from a function when the caller only needs to iterate over that result once.
|
||||
- If an intermediate vector is avoidable, use an `Iterator` instead; most of the time this just amounts to omitting the call to `.collect()` if a single-pass iteration follows afterwards, or returning an `impl Iterator<Item = T>` from a function when the caller only needs to iterate over that result once.
|
||||
- When possible, fill/resize collections "in bulk" instead of pushing a single element in a loop; this is usually (but not always) detected by `clippy`, suggesting to create vectors containing a repeated value with `vec![x; N]` or extending them with `.resize(N, x)`.
|
||||
- When a value is to eventually be consumed in a chain of function calls, pass it by value instead of by reference; this has the following benefits:
|
||||
* It makes the fact that the value is needed by value clear to the caller, who can then potentially reclaim it from the object afterwards if it is "heavy", limiting allocations.
|
||||
|
211
Cargo.lock
generated
211
Cargo.lock
generated
@ -154,9 +154,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.4"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@ -220,9 +220,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.12"
|
||||
version = "2.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
|
||||
checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"bstr",
|
||||
@ -462,9 +462,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.13"
|
||||
version = "4.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
|
||||
checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -472,9 +472,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.12"
|
||||
version = "4.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||
checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -529,15 +529,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.7"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"unicode-width",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -735,6 +735,19 @@ dependencies = [
|
||||
"syn 2.0.46",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown 0.14.2",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.8"
|
||||
@ -823,6 +836,16 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "disassembler"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"leo-ast",
|
||||
"leo-errors",
|
||||
"leo-span",
|
||||
"snarkvm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@ -990,6 +1013,21 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1fd087255f739f4f1aeea69f11b72f8080e9c2e7645cd06955dad4a178a49e3"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
@ -997,6 +1035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1005,6 +1044,17 @@ version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.29"
|
||||
@ -1029,8 +1079,10 @@ version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
@ -1380,6 +1432,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"snarkvm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1387,6 +1440,7 @@ name = "leo-compiler"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"indexmap 1.9.3",
|
||||
"leo-ast",
|
||||
"leo-errors",
|
||||
"leo-package",
|
||||
@ -1413,6 +1467,7 @@ dependencies = [
|
||||
"colored",
|
||||
"derivative",
|
||||
"leo-span",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
@ -1421,6 +1476,7 @@ dependencies = [
|
||||
name = "leo-lang"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"aleo-std",
|
||||
"ansi_term",
|
||||
"assert_cmd",
|
||||
"backtrace",
|
||||
@ -1442,10 +1498,12 @@ dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"reqwest",
|
||||
"retriever",
|
||||
"rusty-hook",
|
||||
"self_update 0.39.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"snarkvm",
|
||||
"sys-info",
|
||||
"test_dir",
|
||||
@ -1460,11 +1518,14 @@ dependencies = [
|
||||
name = "leo-package"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"aleo-std",
|
||||
"indexmap 1.9.3",
|
||||
"lazy_static",
|
||||
"leo-errors",
|
||||
"rand",
|
||||
"retriever",
|
||||
"serde",
|
||||
"serial_test",
|
||||
"snarkvm",
|
||||
"toml 0.8.8",
|
||||
"tracing",
|
||||
@ -1522,6 +1583,7 @@ dependencies = [
|
||||
"backtrace",
|
||||
"clap",
|
||||
"criterion",
|
||||
"indexmap 1.9.3",
|
||||
"leo-compiler",
|
||||
"leo-errors",
|
||||
"leo-span",
|
||||
@ -2180,6 +2242,26 @@ dependencies = [
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "retriever"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"aleo-std",
|
||||
"disassembler",
|
||||
"indexmap 1.9.3",
|
||||
"leo-ast",
|
||||
"leo-errors",
|
||||
"leo-passes",
|
||||
"leo-span",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"toml 0.8.8",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.5"
|
||||
@ -2384,18 +2466,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.35",
|
||||
@ -2447,6 +2529,31 @@ dependencies = [
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test_derive"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.46",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@ -2499,9 +2606,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.2"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -3829,9 +3936,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.9.0"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7830e33f6e25723d41a63f77e434159dad02919f18f55a512b5f16f3b1d77138"
|
||||
checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"flate2",
|
||||
@ -4033,15 +4140,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@ -4060,21 +4158,6 @@ dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@ -4105,12 +4188,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -4123,12 +4200,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
@ -4141,12 +4212,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
@ -4159,12 +4224,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
@ -4177,12 +4236,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
@ -4195,12 +4248,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -4213,12 +4260,6 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
|
22
Cargo.toml
22
Cargo.toml
@ -18,13 +18,10 @@ include = [
|
||||
"leo",
|
||||
"README.md",
|
||||
"LICENSE.md",
|
||||
"examples/lottery/inputs/lottery.in",
|
||||
"examples/lottery/src/main.leo",
|
||||
"examples/lottery/run.sh",
|
||||
"examples/tictactoe/inputs/tictactoe.in",
|
||||
"examples/tictactoe/src/main.leo",
|
||||
"examples/tictactoe/run.sh",
|
||||
"examples/token/inputs/token.in",
|
||||
"examples/token/src/main.leo",
|
||||
"examples/token/run.sh"
|
||||
]
|
||||
@ -41,7 +38,9 @@ members = [
|
||||
"docs/grammar",
|
||||
"errors",
|
||||
"leo/package",
|
||||
"tests/test-framework"
|
||||
"tests/test-framework",
|
||||
"utils/disassembler",
|
||||
"utils/retriever"
|
||||
]
|
||||
|
||||
[workspace.dependencies.snarkvm]
|
||||
@ -59,6 +58,10 @@ default = [ ]
|
||||
ci_skip = [ "leo-compiler/ci_skip" ]
|
||||
noconfig = [ ]
|
||||
|
||||
[dependencies.aleo-std]
|
||||
version = "0.1.18"
|
||||
default-features = false
|
||||
|
||||
[dependencies.leo-ast]
|
||||
path = "./compiler/ast"
|
||||
version = "=1.10.0"
|
||||
@ -83,6 +86,10 @@ version = "=1.10.0"
|
||||
path = "./compiler/span"
|
||||
version = "=1.10.0"
|
||||
|
||||
[dependencies.retriever]
|
||||
path = "./utils/retriever"
|
||||
version = "1.10.0"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.68"
|
||||
|
||||
@ -97,7 +104,7 @@ version = "0.6.1"
|
||||
version = "2.0"
|
||||
|
||||
[dependencies.console]
|
||||
version = "0.15.7"
|
||||
version = "0.15.8"
|
||||
|
||||
[dependencies.dirs]
|
||||
version = "5.0.0"
|
||||
@ -137,6 +144,9 @@ features = [ "derive" ]
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.serial_test]
|
||||
version = "3.0.0"
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
features = [ "circuit", "console" ]
|
||||
@ -161,7 +171,7 @@ version = "^0.6"
|
||||
version = "0.12.1"
|
||||
|
||||
[dev-dependencies.assert_cmd]
|
||||
version = "2.0.12"
|
||||
version = "2.0.13"
|
||||
|
||||
[dev-dependencies.rusty-hook]
|
||||
version = "0.11.2"
|
||||
|
@ -7,8 +7,9 @@
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/AleoHQ/leo"><img src="https://circleci.com/gh/AleoHQ/leo.svg?style=svg&circle-token=00960191919c40be0774e00ce8f7fa1fcaa20c00"></a>
|
||||
<a href="https://codecov.io/gh/AleoHQ/leo"><img src="https://codecov.io/gh/AleoHQ/leo/branch/testnet3/graph/badge.svg?token=S6MWO60SYL"/></a>
|
||||
<a href="https://discord.gg/5v2ynrw2ds"><img src="https://img.shields.io/discord/700454073459015690?logo=discord"/></a>
|
||||
<a href="https://discord.gg/aleo"><img src="https://img.shields.io/discord/700454073459015690?logo=discord"/></a>
|
||||
<a href="https://github.com/AleoHQ/leo/blob/testnet3/CONTRIBUTORS.md"><img src="https://img.shields.io/badge/contributors-393-ee8449"/></a>
|
||||
<a href="https://twitter.com/AleoHQ"><img src="https://img.shields.io/twitter/follow/AleoHQ?style=social"/></a>
|
||||
</p>
|
||||
<div id="top"></div>
|
||||
Leo is a functional, statically-typed programming language built for writing private applications.
|
||||
@ -87,7 +88,7 @@ leo new helloworld
|
||||
cd helloworld
|
||||
|
||||
# build & setup & prove & verify
|
||||
leo run
|
||||
leo run main 0u32 1u32
|
||||
```
|
||||
|
||||
The `leo new` command creates a new Leo project with a given name.
|
||||
|
@ -18,6 +18,9 @@ license = "GPL-3.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.69"
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
|
||||
[dependencies.leo-errors]
|
||||
path = "../../errors"
|
||||
version = "=1.10.0"
|
||||
@ -42,7 +45,7 @@ version = "1.0"
|
||||
features = [ "preserve_order" ]
|
||||
|
||||
[dependencies.smallvec]
|
||||
version = "1.11.2"
|
||||
version = "1.12.0"
|
||||
features = [ "serde" ]
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use leo_errors::Result;
|
||||
use leo_span::{Span, Symbol};
|
||||
use snarkvm::console::program::Identifier as IdentifierCore;
|
||||
|
||||
use crate::{simple_node_impl, Node, NodeID};
|
||||
use serde::{
|
||||
@ -28,6 +29,7 @@ use serde::{
|
||||
Serialize,
|
||||
Serializer,
|
||||
};
|
||||
use snarkvm::prelude::Network;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
@ -152,3 +154,8 @@ impl<'de> Deserialize<'de> for Identifier {
|
||||
deserializer.deserialize_str(IdentifierVisitor)
|
||||
}
|
||||
}
|
||||
impl<N: Network> From<&IdentifierCore<N>> for Identifier {
|
||||
fn from(id: &IdentifierCore<N>) -> Self {
|
||||
Self { name: Symbol::intern(&id.to_string()), span: Default::default(), id: Default::default() }
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Block, Identifier, Input, Node, NodeID, Output, TupleType, Type};
|
||||
use crate::{Block, FinalizeStub, Identifier, Input, Node, NodeID, Output, TupleType, Type};
|
||||
|
||||
use leo_span::Span;
|
||||
|
||||
@ -72,4 +72,17 @@ impl fmt::Display for Finalize {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FinalizeStub> for Finalize {
|
||||
fn from(finalize_stub: FinalizeStub) -> Self {
|
||||
Self::new(
|
||||
finalize_stub.identifier,
|
||||
finalize_stub.input,
|
||||
finalize_stub.output,
|
||||
Block::default(),
|
||||
finalize_stub.span,
|
||||
finalize_stub.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(Finalize);
|
||||
|
@ -38,7 +38,7 @@ pub use output::*;
|
||||
pub mod mode;
|
||||
pub use mode::*;
|
||||
|
||||
use crate::{Block, Identifier, Node, NodeID, TupleType, Type};
|
||||
use crate::{Block, FunctionStub, Identifier, Node, NodeID, TupleType, Type};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -139,6 +139,24 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FunctionStub> for Function {
|
||||
fn from(function: FunctionStub) -> Self {
|
||||
let finalize = function.finalize_stub.map(Finalize::from);
|
||||
Self {
|
||||
annotations: function.annotations,
|
||||
variant: function.variant,
|
||||
identifier: function.identifier,
|
||||
input: function.input,
|
||||
output: function.output,
|
||||
output_type: function.output_type,
|
||||
block: Block::default(),
|
||||
finalize,
|
||||
span: function.span,
|
||||
id: function.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
|
@ -1,29 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use crate::{Expression, Identifier, Mode, Type};
|
||||
|
||||
/// A single definition inside a section in a state or an input file.
|
||||
/// Definitions should be structured as: `<name>: <type_> = <value>;`
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Definition {
|
||||
pub mode: Mode,
|
||||
pub type_: Type,
|
||||
pub name: Identifier,
|
||||
pub value: Expression,
|
||||
pub span: Span,
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{normalize_json_value, remove_key_from_json, Expression, Struct, Type};
|
||||
|
||||
use super::*;
|
||||
use leo_errors::{AstError, Result};
|
||||
|
||||
/// Input data which includes [`ProgramInput`].
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct InputData {
|
||||
pub program_input: ProgramInput,
|
||||
}
|
||||
|
||||
impl InputData {
|
||||
/// Serializes the ast into a JSON string.
|
||||
pub fn to_json_string(&self) -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(&self).map_err(|e| AstError::failed_to_convert_ast_to_json_string(&e))?)
|
||||
}
|
||||
}
|
||||
|
||||
/// A raw unprocessed input or state file data. Used for future conversion
|
||||
/// into [`ProgramInput`].
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct InputAst {
|
||||
pub sections: Vec<Section>,
|
||||
}
|
||||
|
||||
impl InputAst {
|
||||
/// Returns all values of the input AST for execution with `leo run`.
|
||||
pub fn program_inputs(&self, program_name: &str, structs: IndexMap<Symbol, Struct>) -> Vec<String> {
|
||||
self.sections
|
||||
.iter()
|
||||
.filter(|section| section.name() == program_name)
|
||||
.flat_map(|section| {
|
||||
section.definitions.iter().map(|definition| match &definition.type_ {
|
||||
// Handle case where the input may be record.
|
||||
Type::Identifier(identifier) => {
|
||||
match structs.get(&identifier.name) {
|
||||
// TODO: Better error handling.
|
||||
None => panic!(
|
||||
"Input error: A struct or record declaration does not exist for {}.",
|
||||
identifier.name
|
||||
),
|
||||
Some(struct_) => match struct_.is_record {
|
||||
false => definition.value.to_string(),
|
||||
true => match &definition.value {
|
||||
// Print out the record interface with visibility.
|
||||
Expression::Struct(struct_expression) => struct_expression.to_record_string(),
|
||||
_ => panic!("Input error: Expected a struct expression."),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => definition.value.to_string(),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Serializes the `Input` into a JSON Value.
|
||||
pub fn to_json_value(&self) -> Result<serde_json::Value> {
|
||||
Ok(serde_json::to_value(self).map_err(|e| AstError::failed_to_convert_ast_to_json_value(&e))?)
|
||||
}
|
||||
|
||||
/// Serializes the input into a JSON file.
|
||||
pub fn to_json_file(&self, mut path: std::path::PathBuf, file_name: &str) -> Result<()> {
|
||||
path.push(file_name);
|
||||
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
|
||||
let writer = std::io::BufWriter::new(file);
|
||||
Ok(serde_json::to_writer_pretty(writer, &self)
|
||||
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
|
||||
}
|
||||
|
||||
/// Serializes the `Input` into a JSON value and removes keys from object mappings before writing to a file.
|
||||
pub fn to_json_file_without_keys(
|
||||
&self,
|
||||
mut path: std::path::PathBuf,
|
||||
file_name: &str,
|
||||
excluded_keys: &[&str],
|
||||
) -> Result<()> {
|
||||
path.push(file_name);
|
||||
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
|
||||
let writer = std::io::BufWriter::new(file);
|
||||
|
||||
let mut value = self.to_json_value().unwrap();
|
||||
for key in excluded_keys {
|
||||
value = remove_key_from_json(value, key);
|
||||
}
|
||||
value = normalize_json_value(value);
|
||||
|
||||
Ok(serde_json::to_writer_pretty(writer, &value)
|
||||
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, GroupLiteral, IntegerType, Literal, Node, Type, UnaryOperation};
|
||||
use leo_errors::{InputError, LeoError, Result};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InputValue {
|
||||
Address(String),
|
||||
Boolean(bool),
|
||||
Field(String),
|
||||
Group(GroupLiteral),
|
||||
Integer(IntegerType, String),
|
||||
}
|
||||
|
||||
impl TryFrom<(Type, Expression)> for InputValue {
|
||||
type Error = LeoError;
|
||||
|
||||
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
||||
Ok(match value {
|
||||
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
||||
(Type::Address, Literal::Address(value, _, _)) => Self::Address(value),
|
||||
(Type::Boolean, Literal::Boolean(value, _, _)) => Self::Boolean(value),
|
||||
(Type::Field, Literal::Field(value, _, _)) => Self::Field(value),
|
||||
(Type::Group, Literal::Group(value)) => Self::Group(*value),
|
||||
(Type::Integer(expected), Literal::Integer(actual, value, span, _)) => {
|
||||
if expected == actual {
|
||||
Self::Integer(expected, value)
|
||||
} else {
|
||||
return Err(InputError::unexpected_type(expected.to_string(), actual, span).into());
|
||||
}
|
||||
}
|
||||
(x, y) => {
|
||||
return Err(InputError::unexpected_type(x, &y, y.span()).into());
|
||||
}
|
||||
},
|
||||
(type_, Expression::Unary(unary)) if unary.op == UnaryOperation::Negate => {
|
||||
InputValue::try_from((type_, *unary.receiver))?
|
||||
}
|
||||
(_type_, expr) => return Err(InputError::illegal_expression(&expr, expr.span()).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InputValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InputValue::Address(ref address) => write!(f, "{address}"),
|
||||
InputValue::Boolean(ref boolean) => write!(f, "{boolean}"),
|
||||
InputValue::Group(ref group) => write!(f, "{group}"),
|
||||
InputValue::Field(ref field) => write!(f, "{field}"),
|
||||
InputValue::Integer(ref type_, ref number) => write!(f, "{number}{type_:?}"),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Processed Program input.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct ProgramInput {
|
||||
pub main: Definitions,
|
||||
}
|
||||
|
||||
impl TryFrom<InputAst> for ProgramInput {
|
||||
type Error = LeoError;
|
||||
|
||||
fn try_from(input: InputAst) -> Result<Self> {
|
||||
let mut main = IndexMap::new();
|
||||
|
||||
for section in input.sections {
|
||||
let target = match section.name {
|
||||
sym::main => &mut main,
|
||||
_ => return Err(InputError::unexpected_section(&["main"], section.name, section.span).into()),
|
||||
};
|
||||
|
||||
for definition in section.definitions {
|
||||
target.insert(definition.name.name, InputValue::try_from((definition.type_, definition.value))?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ProgramInput { main })
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A single section in an input or a state file.
|
||||
/// An example of a section would be: `[main]`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Section {
|
||||
pub name: Symbol,
|
||||
pub definitions: Vec<Definition>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Section {
|
||||
pub fn name(&self) -> String {
|
||||
self.name.to_string()
|
||||
}
|
||||
}
|
@ -40,9 +40,6 @@ pub use self::functions::*;
|
||||
pub mod groups;
|
||||
pub use self::groups::*;
|
||||
|
||||
pub mod input;
|
||||
pub use self::input::*;
|
||||
|
||||
pub mod mapping;
|
||||
pub use self::mapping::*;
|
||||
|
||||
@ -59,6 +56,10 @@ pub mod types;
|
||||
pub use self::types::*;
|
||||
|
||||
pub mod value;
|
||||
|
||||
pub mod stub;
|
||||
pub use self::stub::*;
|
||||
|
||||
pub use self::value::*;
|
||||
|
||||
pub use common::node::*;
|
||||
|
@ -19,6 +19,7 @@ use crate::{Identifier, Node, NodeID, Type};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::prelude::{Mapping as MappingCore, Network};
|
||||
use std::fmt;
|
||||
|
||||
/// A mapping declaration, e.g `mapping balances: address => u128`.
|
||||
@ -36,6 +37,17 @@ pub struct Mapping {
|
||||
pub id: NodeID,
|
||||
}
|
||||
|
||||
impl<N: Network> From<&MappingCore<N>> for Mapping {
|
||||
fn from(mapping: &MappingCore<N>) -> Self {
|
||||
Self {
|
||||
identifier: Identifier::from(mapping.name()),
|
||||
key_type: Type::from(mapping.key().plaintext_type()),
|
||||
value_type: Type::from(mapping.value().plaintext_type()),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Mapping {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "mapping {}: {} => {}", self.identifier, self.key_type, self.value_type)
|
||||
|
@ -417,6 +417,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
.into_iter()
|
||||
.map(|(id, import)| (id, (self.reconstruct_import(import.0), import.1)))
|
||||
.collect(),
|
||||
stubs: input.stubs.into_iter().map(|(id, stub)| (id, self.reconstruct_stub(stub))).collect(),
|
||||
program_scopes: input
|
||||
.program_scopes
|
||||
.into_iter()
|
||||
@ -425,6 +426,18 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_stub(&mut self, input: Stub) -> Stub {
|
||||
Stub {
|
||||
imports: input.imports,
|
||||
stub_id: input.stub_id,
|
||||
consts: input.consts,
|
||||
structs: input.structs,
|
||||
mappings: input.mappings,
|
||||
span: input.span,
|
||||
functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function_stub(f))).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
|
||||
ProgramScope {
|
||||
program_id: input.program_id,
|
||||
@ -466,6 +479,10 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub) -> FunctionStub {
|
||||
input
|
||||
}
|
||||
|
||||
fn reconstruct_struct(&mut self, input: Struct) -> Struct {
|
||||
input
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
|
||||
pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
fn visit_program(&mut self, input: &'a Program) {
|
||||
input.imports.values().for_each(|import| self.visit_import(&import.0));
|
||||
|
||||
input.stubs.values().for_each(|stub| self.visit_stub(stub));
|
||||
input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
|
||||
}
|
||||
|
||||
@ -236,6 +236,8 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
|
||||
}
|
||||
|
||||
fn visit_stub(&mut self, _input: &'a Stub) {}
|
||||
|
||||
fn visit_import(&mut self, input: &'a Program) {
|
||||
self.visit_program(input)
|
||||
}
|
||||
@ -250,4 +252,8 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
self.visit_block(&finalize.block);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, _input: &'a FunctionStub) {}
|
||||
|
||||
fn visit_struct_stub(&mut self, _input: &'a Struct) {}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ pub use program_scope::*;
|
||||
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use crate::Stub;
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -33,6 +34,8 @@ use std::fmt;
|
||||
pub struct Program {
|
||||
/// A map from import names to import definitions.
|
||||
pub imports: IndexMap<Symbol, (Program, Span)>,
|
||||
/// A map from program stub names to program stub scopes.
|
||||
pub stubs: IndexMap<Symbol, Stub>,
|
||||
/// A map from program names to program scopes.
|
||||
pub program_scopes: IndexMap<Symbol, ProgramScope>,
|
||||
}
|
||||
@ -42,6 +45,10 @@ impl fmt::Display for Program {
|
||||
for (id, _import) in self.imports.iter() {
|
||||
writeln!(f, "import {id}.leo;")?;
|
||||
}
|
||||
for (_, stub) in self.stubs.iter() {
|
||||
stub.fmt(f)?;
|
||||
writeln!(f,)?;
|
||||
}
|
||||
for (_, program_scope) in self.program_scopes.iter() {
|
||||
program_scope.fmt(f)?;
|
||||
writeln!(f,)?;
|
||||
@ -53,6 +60,6 @@ impl fmt::Display for Program {
|
||||
impl Default for Program {
|
||||
/// Constructs an empty program node.
|
||||
fn default() -> Self {
|
||||
Self { imports: IndexMap::new(), program_scopes: IndexMap::new() }
|
||||
Self { imports: IndexMap::new(), stubs: IndexMap::new(), program_scopes: IndexMap::new() }
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ use crate::Identifier;
|
||||
|
||||
use core::fmt;
|
||||
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use snarkvm::{console::program::ProgramID, prelude::Network};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// An identifier for a program that is eventually deployed to the network.
|
||||
@ -92,3 +93,9 @@ impl<'de> Deserialize<'de> for ProgramId {
|
||||
deserializer.deserialize_str(ProgramIdVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network> From<&ProgramID<N>> for ProgramId {
|
||||
fn from(program: &ProgramID<N>) -> Self {
|
||||
Self { name: Identifier::from(program.name()), network: Identifier::from(program.network()) }
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
//! A Leo program scope consists of struct, function, and mapping definitions.
|
||||
|
||||
use crate::{ConstDeclaration, Function, Mapping, ProgramId, Struct};
|
||||
use crate::{ConstDeclaration, Function, Mapping, ProgramId, Struct, Stub};
|
||||
|
||||
use leo_span::{Span, Symbol};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -39,6 +39,23 @@ pub struct ProgramScope {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl From<Stub> for ProgramScope {
|
||||
fn from(stub: Stub) -> Self {
|
||||
Self {
|
||||
program_id: stub.stub_id,
|
||||
consts: stub.consts,
|
||||
structs: stub.structs,
|
||||
mappings: stub.mappings,
|
||||
functions: stub
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(symbol, function)| (symbol, Function::from(function)))
|
||||
.collect(),
|
||||
span: stub.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProgramScope {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "program {} {{", self.program_id)?;
|
||||
|
@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A block `{ [stmt]* }` consisting of a list of statements to execute in order.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Default)]
|
||||
pub struct Block {
|
||||
/// The list of statements to execute.
|
||||
pub statements: Vec<Statement>,
|
||||
|
@ -17,12 +17,21 @@
|
||||
pub mod member;
|
||||
pub use member::*;
|
||||
|
||||
use crate::{Identifier, Node, NodeID};
|
||||
use crate::{Identifier, Mode, Node, NodeID, Type};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
use snarkvm::{
|
||||
console::program::{RecordType, StructType},
|
||||
prelude::{
|
||||
EntryType::{Constant, Private, Public},
|
||||
Network,
|
||||
},
|
||||
};
|
||||
|
||||
/// A struct type definition, e.g., `struct Foo { my_field: Bar }`.
|
||||
/// In some languages these are called `struct`s.
|
||||
///
|
||||
@ -70,10 +79,68 @@ impl fmt::Display for Struct {
|
||||
f.write_str(if self.is_record { "record" } else { "struct" })?;
|
||||
writeln!(f, " {} {{ ", self.identifier)?;
|
||||
for field in self.members.iter() {
|
||||
writeln!(f, " {field}")?;
|
||||
writeln!(f, " {field}")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
write!(f, " }}")
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(Struct);
|
||||
|
||||
impl<N: Network> From<&StructType<N>> for Struct {
|
||||
fn from(input: &StructType<N>) -> Self {
|
||||
Self {
|
||||
identifier: Identifier::from(input.name()),
|
||||
members: input
|
||||
.members()
|
||||
.iter()
|
||||
.map(|(id, type_)| Member {
|
||||
mode: Mode::None,
|
||||
identifier: Identifier::from(id),
|
||||
type_: Type::from(type_),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})
|
||||
.collect(),
|
||||
is_record: false,
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network> From<&RecordType<N>> for Struct {
|
||||
fn from(input: &RecordType<N>) -> Self {
|
||||
Self {
|
||||
identifier: Identifier::from(input.name()),
|
||||
members: [
|
||||
vec![Member {
|
||||
mode: if input.owner().is_private() { Mode::Public } else { Mode::Private },
|
||||
identifier: Identifier::new(Symbol::intern("owner"), Default::default()),
|
||||
type_: Type::Address,
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}],
|
||||
input
|
||||
.entries()
|
||||
.iter()
|
||||
.map(|(id, entry)| Member {
|
||||
mode: if input.owner().is_public() { Mode::Public } else { Mode::Private },
|
||||
identifier: Identifier::from(id),
|
||||
type_: match entry {
|
||||
Public(t) => Type::from(t),
|
||||
Private(t) => Type::from(t),
|
||||
Constant(t) => Type::from(t),
|
||||
},
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})
|
||||
.collect_vec(),
|
||||
]
|
||||
.concat(),
|
||||
is_record: true,
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
101
compiler/ast/src/stub/finalize_stub.rs
Normal file
101
compiler/ast/src/stub/finalize_stub.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Finalize, FunctionInput, Identifier, Input, Mode, Node, NodeID, Output, TupleType, Type};
|
||||
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use core::fmt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::{
|
||||
prelude::{
|
||||
FinalizeType::{Future, Plaintext},
|
||||
Network,
|
||||
},
|
||||
synthesizer::program::{CommandTrait, FinalizeCore},
|
||||
};
|
||||
|
||||
/// A finalize stub.
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)]
|
||||
pub struct FinalizeStub {
|
||||
/// The finalize identifier.
|
||||
pub identifier: Identifier,
|
||||
/// The finalize block's input parameters.
|
||||
pub input: Vec<Input>,
|
||||
/// The finalize blocks's output declaration.
|
||||
pub output: Vec<Output>,
|
||||
/// The finalize block's output type.
|
||||
pub output_type: Type,
|
||||
/// The entire span of the finalize stub.
|
||||
pub span: Span,
|
||||
/// The ID of the node.
|
||||
pub id: NodeID,
|
||||
}
|
||||
|
||||
impl FinalizeStub {
|
||||
/// Create a new finalize stub.
|
||||
pub fn new(identifier: Identifier, input: Vec<Input>, output: Vec<Output>, span: Span, id: NodeID) -> Self {
|
||||
let output_type = match output.len() {
|
||||
0 => Type::Unit,
|
||||
1 => output[0].type_(),
|
||||
_ => Type::Tuple(TupleType::new(output.iter().map(|output| output.type_()).collect())),
|
||||
};
|
||||
|
||||
Self { identifier, input, output, output_type, span, id }
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network, Command: CommandTrait<N>> From<&FinalizeCore<N, Command>> for FinalizeStub {
|
||||
fn from(finalize: &FinalizeCore<N, Command>) -> Self {
|
||||
let mut inputs = Vec::new();
|
||||
|
||||
finalize.inputs().iter().enumerate().for_each(|(index, input)| {
|
||||
let arg_name = Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default());
|
||||
match input.finalize_type() {
|
||||
Plaintext(val) => inputs.push(Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::None,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})),
|
||||
Future(_) => {} // Don't need to worry about nested futures
|
||||
}
|
||||
});
|
||||
|
||||
Self::new(Identifier::from(finalize.name()), inputs, Vec::new(), Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Finalize> for FinalizeStub {
|
||||
fn from(finalize: Finalize) -> Self {
|
||||
Self::new(finalize.identifier, finalize.input, finalize.output, Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FinalizeStub {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
|
||||
let returns = match self.output.len() {
|
||||
0 => "()".to_string(),
|
||||
1 => self.output[0].to_string(),
|
||||
_ => format!("({})", self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")),
|
||||
};
|
||||
write!(f, " finalize {}({parameters}) -> {returns}", self.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(FinalizeStub);
|
349
compiler/ast/src/stub/function_stub.rs
Normal file
349
compiler/ast/src/stub/function_stub.rs
Normal file
@ -0,0 +1,349 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
finalize_stub::*,
|
||||
Annotation,
|
||||
External,
|
||||
Function,
|
||||
FunctionInput,
|
||||
FunctionOutput,
|
||||
Identifier,
|
||||
Input,
|
||||
Mode,
|
||||
Node,
|
||||
NodeID,
|
||||
Output,
|
||||
ProgramId,
|
||||
TupleType,
|
||||
Type,
|
||||
Variant,
|
||||
};
|
||||
use leo_span::{sym, Span, Symbol};
|
||||
|
||||
use crate::Type::Identifier as IdentifierType;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::{
|
||||
console::program::RegisterType::{ExternalRecord, Future, Plaintext, Record},
|
||||
prelude::{Network, ValueType},
|
||||
synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// A function stub definition.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct FunctionStub {
|
||||
/// Annotations on the function.
|
||||
pub annotations: Vec<Annotation>,
|
||||
/// Is this function a transition, inlined, or a regular function?.
|
||||
pub variant: Variant,
|
||||
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
|
||||
pub identifier: Identifier,
|
||||
/// The function's input parameters.
|
||||
pub input: Vec<Input>,
|
||||
/// The function's output declarations.
|
||||
pub output: Vec<Output>,
|
||||
/// The function's output type.
|
||||
pub output_type: Type,
|
||||
/// An optional finalize stub
|
||||
pub finalize_stub: Option<FinalizeStub>,
|
||||
/// The entire span of the function definition.
|
||||
pub span: Span,
|
||||
/// The ID of the node.
|
||||
pub id: NodeID,
|
||||
}
|
||||
|
||||
impl PartialEq for FunctionStub {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.identifier == other.identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FunctionStub {}
|
||||
|
||||
impl FunctionStub {
|
||||
/// Initialize a new function.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
annotations: Vec<Annotation>,
|
||||
variant: Variant,
|
||||
identifier: Identifier,
|
||||
input: Vec<Input>,
|
||||
output: Vec<Output>,
|
||||
finalize_stub: Option<FinalizeStub>,
|
||||
span: Span,
|
||||
id: NodeID,
|
||||
) -> Self {
|
||||
// Determine the output type of the function
|
||||
let get_output_type = |output: &Output| match &output {
|
||||
Output::Internal(output) => output.type_.clone(),
|
||||
Output::External(output) => output.type_(),
|
||||
};
|
||||
|
||||
let output_type = match output.len() {
|
||||
0 => Type::Unit,
|
||||
1 => get_output_type(&output[0]),
|
||||
_ => Type::Tuple(TupleType::new(output.iter().map(get_output_type).collect())),
|
||||
};
|
||||
|
||||
FunctionStub { annotations, variant, identifier, input, output, output_type, finalize_stub, span, id }
|
||||
}
|
||||
|
||||
/// Returns function name.
|
||||
pub fn name(&self) -> Symbol {
|
||||
self.identifier.name
|
||||
}
|
||||
|
||||
/// Returns `true` if the function name is `main`.
|
||||
pub fn is_main(&self) -> bool {
|
||||
self.name() == sym::main
|
||||
}
|
||||
|
||||
///
|
||||
/// Private formatting method used for optimizing [fmt::Debug] and [fmt::Display] implementations.
|
||||
///
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.variant {
|
||||
Variant::Inline => write!(f, "inline ")?,
|
||||
Variant::Standard => write!(f, "function ")?,
|
||||
Variant::Transition => write!(f, "transition ")?,
|
||||
}
|
||||
write!(f, "{}", self.identifier)?;
|
||||
|
||||
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
|
||||
let returns = match self.output.len() {
|
||||
0 => "()".to_string(),
|
||||
1 => self.output[0].to_string(),
|
||||
_ => self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","),
|
||||
};
|
||||
write!(f, "({parameters}) -> {returns}")?;
|
||||
|
||||
if let Some(finalize) = &self.finalize_stub {
|
||||
let parameters = finalize.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
|
||||
write!(f, " finalize ({parameters})")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Function> for FunctionStub {
|
||||
fn from(function: Function) -> Self {
|
||||
Self {
|
||||
annotations: function.annotations,
|
||||
variant: function.variant,
|
||||
identifier: function.identifier,
|
||||
input: function.input,
|
||||
output: function.output,
|
||||
output_type: function.output_type,
|
||||
finalize_stub: function.finalize.map(FinalizeStub::from),
|
||||
span: function.span,
|
||||
id: function.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network, Instruction: InstructionTrait<N>> From<&ClosureCore<N, Instruction>> for FunctionStub {
|
||||
fn from(closure: &ClosureCore<N, Instruction>) -> Self {
|
||||
let outputs = closure
|
||||
.outputs()
|
||||
.iter()
|
||||
.map(|output| match output.register_type() {
|
||||
Plaintext(val) => Output::Internal(FunctionOutput {
|
||||
mode: Mode::None,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
Record(_) => panic!("Closures do not return records"),
|
||||
ExternalRecord(_) => panic!("Closures do not return external records"),
|
||||
Future(_) => panic!("Closures do not return futures"),
|
||||
})
|
||||
.collect_vec();
|
||||
let output_vec = outputs
|
||||
.iter()
|
||||
.map(|output| match output {
|
||||
Output::Internal(output) => output.type_.clone(),
|
||||
Output::External(_) => panic!("Closures do not return external records"),
|
||||
})
|
||||
.collect_vec();
|
||||
let output_type = match output_vec.len() {
|
||||
0 => Type::Unit,
|
||||
1 => output_vec[0].clone(),
|
||||
_ => Type::Tuple(TupleType::new(output_vec)),
|
||||
};
|
||||
Self {
|
||||
annotations: Vec::new(),
|
||||
variant: Variant::Standard,
|
||||
identifier: Identifier::from(closure.name()),
|
||||
input: closure
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| {
|
||||
let arg_name = Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default());
|
||||
match input.register_type() {
|
||||
Plaintext(val) => Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::None,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
Record(_) => panic!("Closures do not contain records as inputs"),
|
||||
ExternalRecord(_) => panic!("Closures do not contain external records as inputs"),
|
||||
Future(_) => panic!("Closures do not contain futures as inputs"),
|
||||
}
|
||||
})
|
||||
.collect_vec(),
|
||||
output: outputs,
|
||||
output_type,
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
finalize_stub: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>
|
||||
From<&FunctionCore<N, Instruction, Command>> for FunctionStub
|
||||
{
|
||||
fn from(function: &FunctionCore<N, Instruction, Command>) -> Self {
|
||||
let outputs = function
|
||||
.outputs()
|
||||
.iter()
|
||||
.map(|output| match output.value_type() {
|
||||
ValueType::Constant(val) => vec![Output::Internal(FunctionOutput {
|
||||
mode: Mode::Constant,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})],
|
||||
ValueType::Public(val) => vec![Output::Internal(FunctionOutput {
|
||||
mode: Mode::Public,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})],
|
||||
ValueType::Private(val) => vec![Output::Internal(FunctionOutput {
|
||||
mode: Mode::Private,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})],
|
||||
ValueType::Record(id) => vec![Output::Internal(FunctionOutput {
|
||||
mode: Mode::None,
|
||||
type_: IdentifierType(Identifier::from(id)),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})],
|
||||
ValueType::ExternalRecord(loc) => vec![Output::External(External {
|
||||
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
|
||||
program_name: ProgramId::from(loc.program_id()).name,
|
||||
record: Identifier::from(loc.resource()),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})],
|
||||
ValueType::Future(_) => Vec::new(), // Don't include futures in the output signature
|
||||
})
|
||||
.collect_vec()
|
||||
.concat();
|
||||
let output_vec = outputs
|
||||
.iter()
|
||||
.map(|output| match output {
|
||||
Output::Internal(output) => output.type_.clone(),
|
||||
Output::External(output) => Type::Identifier(output.record),
|
||||
})
|
||||
.collect_vec();
|
||||
let output_type = match output_vec.len() {
|
||||
0 => Type::Unit,
|
||||
1 => output_vec[0].clone(),
|
||||
_ => Type::Tuple(TupleType::new(output_vec)),
|
||||
};
|
||||
|
||||
Self {
|
||||
annotations: Vec::new(),
|
||||
variant: Variant::Transition,
|
||||
identifier: Identifier::from(function.name()),
|
||||
input: function
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| {
|
||||
let arg_name = Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default());
|
||||
match input.value_type() {
|
||||
ValueType::Constant(val) => Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::Constant,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::Public(val) => Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::Public,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::Private(val) => Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::Private,
|
||||
type_: Type::from(val),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::Record(id) => Input::Internal(FunctionInput {
|
||||
identifier: arg_name,
|
||||
mode: Mode::None,
|
||||
type_: IdentifierType(Identifier::from(id)),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::ExternalRecord(loc) => Input::External(External {
|
||||
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
|
||||
program_name: ProgramId::from(loc.program_id()).name,
|
||||
record: Identifier::from(loc.resource()),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::Future(_) => panic!("Functions do not contain futures as inputs"),
|
||||
}
|
||||
})
|
||||
.collect_vec(),
|
||||
output: outputs,
|
||||
output_type,
|
||||
finalize_stub: function.finalize_logic().map(FinalizeStub::from),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FunctionStub {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FunctionStub {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(FunctionStub);
|
84
compiler/ast/src/stub/mod.rs
Normal file
84
compiler/ast/src/stub/mod.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! A stub contains function templates as well as definitions for mappings, structs, records, and constants.
|
||||
|
||||
pub mod finalize_stub;
|
||||
pub use finalize_stub::*;
|
||||
pub mod function_stub;
|
||||
pub use function_stub::*;
|
||||
|
||||
use crate::{ConstDeclaration, Identifier, Mapping, NodeID, ProgramId, Struct};
|
||||
use leo_span::{Span, Symbol};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Stores the Leo stub abstract syntax tree.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stub {
|
||||
/// A vector of imported programs.
|
||||
pub imports: Vec<ProgramId>,
|
||||
/// The stub id
|
||||
pub stub_id: ProgramId,
|
||||
/// A vector of const definitions.
|
||||
pub consts: Vec<(Symbol, ConstDeclaration)>,
|
||||
/// A vector of struct definitions.
|
||||
pub structs: Vec<(Symbol, Struct)>,
|
||||
/// A vector of mapping definitions.
|
||||
pub mappings: Vec<(Symbol, Mapping)>,
|
||||
/// A vector of function stub definitions.
|
||||
pub functions: Vec<(Symbol, FunctionStub)>,
|
||||
/// The span associated with the stub.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Default for Stub {
|
||||
/// Constructs an empty program stub
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
imports: Vec::new(),
|
||||
stub_id: ProgramId {
|
||||
name: Identifier::new(Symbol::intern(""), NodeID::default()),
|
||||
network: Identifier::new(Symbol::intern(""), NodeID::default()),
|
||||
},
|
||||
consts: Vec::new(),
|
||||
structs: Vec::new(),
|
||||
mappings: Vec::new(),
|
||||
functions: Vec::new(),
|
||||
span: Span::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Stub {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "stub {} {{", self.stub_id)?;
|
||||
for import in self.imports.iter() {
|
||||
writeln!(f, " import {import}")?;
|
||||
}
|
||||
for (_, mapping) in self.mappings.iter() {
|
||||
writeln!(f, " {mapping}")?;
|
||||
}
|
||||
for (_, struct_) in self.structs.iter() {
|
||||
writeln!(f, " {struct_}")?;
|
||||
}
|
||||
for (_, function) in self.functions.iter() {
|
||||
writeln!(f, " {function}")?;
|
||||
}
|
||||
writeln!(f, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -15,8 +15,10 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{NonNegativeNumber, Type};
|
||||
use snarkvm::console::program::ArrayType as ConsoleArrayType;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::prelude::Network;
|
||||
use std::fmt;
|
||||
|
||||
/// An array type.
|
||||
@ -51,6 +53,15 @@ impl ArrayType {
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network> From<&ConsoleArrayType<N>> for ArrayType {
|
||||
fn from(array_type: &ConsoleArrayType<N>) -> Self {
|
||||
Self {
|
||||
element_type: Box::new(Type::from(array_type.next_element_type())),
|
||||
length: NonNegativeNumber::from(array_type.length().to_string().replace("u32", "")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ArrayType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "[{}; {}]", self.element_type, self.length)
|
||||
|
@ -14,10 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ArrayType, Identifier, IntegerType, MappingType, TupleType};
|
||||
use crate::{common, ArrayType, Identifier, IntegerType, MappingType, TupleType};
|
||||
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::prelude::{
|
||||
Network,
|
||||
PlaintextType,
|
||||
PlaintextType::{Array, Literal, Struct},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// Explicit type used for defining a variable or expression type
|
||||
@ -108,3 +113,31 @@ impl fmt::Display for Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network> From<&PlaintextType<N>> for Type {
|
||||
fn from(t: &PlaintextType<N>) -> Self {
|
||||
match t {
|
||||
Literal(lit) => match lit {
|
||||
snarkvm::prelude::LiteralType::Address => Type::Address,
|
||||
snarkvm::prelude::LiteralType::Boolean => Type::Boolean,
|
||||
snarkvm::prelude::LiteralType::Field => Type::Field,
|
||||
snarkvm::prelude::LiteralType::Group => Type::Group,
|
||||
snarkvm::prelude::LiteralType::U8 => Type::Integer(IntegerType::U8),
|
||||
snarkvm::prelude::LiteralType::U16 => Type::Integer(IntegerType::U16),
|
||||
snarkvm::prelude::LiteralType::U32 => Type::Integer(IntegerType::U32),
|
||||
snarkvm::prelude::LiteralType::U64 => Type::Integer(IntegerType::U64),
|
||||
snarkvm::prelude::LiteralType::U128 => Type::Integer(IntegerType::U128),
|
||||
snarkvm::prelude::LiteralType::I8 => Type::Integer(IntegerType::I8),
|
||||
snarkvm::prelude::LiteralType::I16 => Type::Integer(IntegerType::I16),
|
||||
snarkvm::prelude::LiteralType::I32 => Type::Integer(IntegerType::I32),
|
||||
snarkvm::prelude::LiteralType::I64 => Type::Integer(IntegerType::I64),
|
||||
snarkvm::prelude::LiteralType::I128 => Type::Integer(IntegerType::I128),
|
||||
snarkvm::prelude::LiteralType::Scalar => Type::Scalar,
|
||||
snarkvm::prelude::LiteralType::Signature => Type::Signature,
|
||||
snarkvm::prelude::LiteralType::String => Type::String,
|
||||
},
|
||||
Struct(s) => Type::Identifier(common::Identifier::from(s)),
|
||||
Array(array) => Type::Array(ArrayType::from(array)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,10 @@ version = "=1.10.0"
|
||||
[dependencies.sha2]
|
||||
version = "0.10"
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.9"
|
||||
features = []
|
||||
|
||||
[dev-dependencies.leo-test-framework]
|
||||
path = "../../tests/test-framework"
|
||||
|
||||
@ -61,7 +65,7 @@ workspace = true
|
||||
version = "1.10.2"
|
||||
|
||||
[dev-dependencies.serde]
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
features = [ "derive" ]
|
||||
|
||||
[dev-dependencies.serde_yaml]
|
||||
@ -72,4 +76,4 @@ version = "3.9"
|
||||
|
||||
[features]
|
||||
default = [ ]
|
||||
ci_skip = [ "leo-ast/ci_skip" ]
|
||||
ci_skip = [ "leo-ast/ci_skip" ]
|
@ -17,17 +17,18 @@
|
||||
//! The compiler for Leo programs.
|
||||
//!
|
||||
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
|
||||
pub use leo_ast::{Ast, InputAst};
|
||||
use leo_ast::{NodeBuilder, Program};
|
||||
pub use leo_ast::Ast;
|
||||
use leo_ast::{NodeBuilder, Program, Stub};
|
||||
use leo_errors::{emitter::Handler, CompilerError, Result};
|
||||
pub use leo_passes::SymbolTable;
|
||||
use leo_passes::*;
|
||||
use leo_span::{source_map::FileName, symbol::with_session_globals};
|
||||
use leo_span::{source_map::FileName, symbol::with_session_globals, Symbol};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use crate::CompilerOptions;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
|
||||
/// The primary entry point of the Leo compiler.
|
||||
#[derive(Clone)]
|
||||
@ -44,8 +45,6 @@ pub struct Compiler<'a> {
|
||||
pub network: String,
|
||||
/// The AST for the program.
|
||||
pub ast: Ast,
|
||||
/// The input ast for the program if it exists.
|
||||
pub input_ast: Option<InputAst>,
|
||||
/// Options configuring compilation.
|
||||
compiler_options: CompilerOptions,
|
||||
/// The `NodeCounter` used to generate sequentially increasing `NodeID`s.
|
||||
@ -54,6 +53,8 @@ pub struct Compiler<'a> {
|
||||
assigner: Assigner,
|
||||
/// The type table.
|
||||
type_table: TypeTable,
|
||||
/// The stubs for imported programs. Produced by `Retriever` module.
|
||||
import_stubs: IndexMap<Symbol, Stub>,
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
@ -65,6 +66,7 @@ impl<'a> Compiler<'a> {
|
||||
main_file_path: PathBuf,
|
||||
output_directory: PathBuf,
|
||||
compiler_options: Option<CompilerOptions>,
|
||||
import_stubs: IndexMap<Symbol, Stub>,
|
||||
) -> Self {
|
||||
let node_builder = NodeBuilder::default();
|
||||
let assigner = Assigner::default();
|
||||
@ -76,10 +78,10 @@ impl<'a> Compiler<'a> {
|
||||
program_name,
|
||||
network,
|
||||
ast: Ast::new(Program::default()),
|
||||
input_ast: None,
|
||||
compiler_options: compiler_options.unwrap_or_default(),
|
||||
node_builder,
|
||||
assigner,
|
||||
import_stubs,
|
||||
type_table,
|
||||
}
|
||||
}
|
||||
@ -136,37 +138,6 @@ impl<'a> Compiler<'a> {
|
||||
self.parse_program_from_string(&program_string, FileName::Real(self.main_file_path.clone()))
|
||||
}
|
||||
|
||||
/// Parses and stores the input file, constructs a syntax tree, and generates a program input.
|
||||
pub fn parse_input(&mut self, input_file_path: PathBuf) -> Result<()> {
|
||||
if input_file_path.exists() {
|
||||
// Load the input file into the source map.
|
||||
let input_sf = with_session_globals(|s| s.source_map.load_file(&input_file_path))
|
||||
.map_err(|e| CompilerError::file_read_error(&input_file_path, e))?;
|
||||
|
||||
// Parse and serialize it.
|
||||
let input_ast =
|
||||
leo_parser::parse_input(self.handler, &self.node_builder, &input_sf.src, input_sf.start_pos)?;
|
||||
if self.compiler_options.output.initial_ast {
|
||||
// Write the input AST snapshot post parsing.
|
||||
if self.compiler_options.output.ast_spans_enabled {
|
||||
input_ast.to_json_file(
|
||||
self.output_directory.clone(),
|
||||
&format!("{}.initial_input_ast.json", self.program_name),
|
||||
)?;
|
||||
} else {
|
||||
input_ast.to_json_file_without_keys(
|
||||
self.output_directory.clone(),
|
||||
&format!("{}.initial_input_ast.json", self.program_name),
|
||||
&["span"],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.input_ast = Some(input_ast);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the symbol table pass.
|
||||
pub fn symbol_table_pass(&self) -> Result<SymbolTable> {
|
||||
let symbol_table = SymbolTableCreator::do_pass((&self.ast, self.handler))?;
|
||||
@ -321,14 +292,16 @@ impl<'a> Compiler<'a> {
|
||||
}
|
||||
|
||||
/// Returns a compiled Leo program.
|
||||
pub fn compile(&mut self) -> Result<(SymbolTable, String)> {
|
||||
pub fn compile(&mut self) -> Result<String> {
|
||||
// Parse the program.
|
||||
self.parse_program()?;
|
||||
// Copy the dependencies specified in `program.json` into the AST.
|
||||
self.add_import_stubs()?;
|
||||
// Run the intermediate compiler stages.
|
||||
let (symbol_table, struct_graph, call_graph) = self.compiler_stages()?;
|
||||
// Run code generation.
|
||||
let bytecode = self.code_generation_pass(&symbol_table, &struct_graph, &call_graph)?;
|
||||
Ok((symbol_table, bytecode))
|
||||
Ok(bytecode)
|
||||
}
|
||||
|
||||
/// Writes the AST to a JSON file.
|
||||
@ -361,4 +334,41 @@ impl<'a> Compiler<'a> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Merges the dependencies defined in `program.json` with the dependencies imported in `.leo` file
|
||||
fn add_import_stubs(&mut self) -> Result<()> {
|
||||
// Create a list of both the explicit dependencies specified in the `.leo` file, as well as the implicit ones derived from those dependencies.
|
||||
let (mut unexplored, mut explored): (IndexSet<Symbol>, IndexSet<Symbol>) =
|
||||
(self.ast.ast.imports.keys().cloned().collect(), IndexSet::new());
|
||||
while !unexplored.is_empty() {
|
||||
let mut current_dependencies: IndexSet<Symbol> = IndexSet::new();
|
||||
for program_name in unexplored.iter() {
|
||||
if let Some(stub) = self.import_stubs.get(program_name) {
|
||||
// Add the program to the explored set
|
||||
explored.insert(*program_name);
|
||||
for dependency in stub.imports.iter() {
|
||||
// If dependency is already explored then don't need to re-explore it
|
||||
if explored.insert(dependency.name.name) {
|
||||
current_dependencies.insert(dependency.name.name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CompilerError::imported_program_not_found(
|
||||
self.program_name.clone(),
|
||||
*program_name,
|
||||
self.ast.ast.imports[program_name].1,
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
// Create next batch to explore
|
||||
unexplored = current_dependencies;
|
||||
}
|
||||
|
||||
// Combine the dependencies from `program.json` and `.leo` file while preserving the post-order
|
||||
self.ast.ast.stubs =
|
||||
self.import_stubs.clone().into_iter().filter(|(program_name, _)| explored.contains(program_name)).collect();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ pub struct OutputOptions {
|
||||
pub ast_spans_enabled: bool,
|
||||
/// If enabled writes the AST after parsing.
|
||||
pub initial_ast: bool,
|
||||
/// If enabled writes the input AST after parsing.
|
||||
pub initial_input_ast: bool,
|
||||
/// If enabled writes the AST after loop unrolling.
|
||||
pub unrolled_ast: bool,
|
||||
/// If enabled writes the AST after static single assignment.
|
||||
|
@ -91,7 +91,6 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
|
||||
type_checked_symbol_table: true,
|
||||
unrolled_symbol_table: true,
|
||||
ast_spans_enabled: false,
|
||||
initial_input_ast: true,
|
||||
initial_ast: true,
|
||||
unrolled_ast: true,
|
||||
ssa_ast: true,
|
||||
|
@ -105,7 +105,6 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
|
||||
type_checked_symbol_table: true,
|
||||
unrolled_symbol_table: true,
|
||||
ast_spans_enabled: false,
|
||||
initial_input_ast: true,
|
||||
initial_ast: true,
|
||||
unrolled_ast: true,
|
||||
ssa_ast: true,
|
||||
|
@ -29,6 +29,7 @@ use leo_test_framework::{test::TestConfig, Test};
|
||||
|
||||
use snarkvm::prelude::*;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use leo_ast::ProgramVisitor;
|
||||
use snarkvm::{file::Manifest, package::Package};
|
||||
use std::{
|
||||
@ -142,7 +143,15 @@ pub fn new_compiler(
|
||||
let output_dir = PathBuf::from("/tmp/output/");
|
||||
fs::create_dir_all(output_dir.clone()).unwrap();
|
||||
|
||||
Compiler::new(String::from("test"), String::from("aleo"), handler, main_file_path, output_dir, compiler_options)
|
||||
Compiler::new(
|
||||
String::from("test"),
|
||||
String::from("aleo"),
|
||||
handler,
|
||||
main_file_path,
|
||||
output_dir,
|
||||
compiler_options,
|
||||
IndexMap::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_program<'a>(
|
||||
|
@ -48,7 +48,7 @@ version = "1.0"
|
||||
features = [ "derive" ]
|
||||
|
||||
[dependencies.smallvec]
|
||||
version = "1.11"
|
||||
version = "1.12"
|
||||
|
||||
[dependencies.tracing]
|
||||
version = "0.1"
|
||||
|
@ -1,70 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use leo_ast::NodeBuilder;
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
use leo_span::symbol::create_session_if_not_set_then;
|
||||
|
||||
use clap::Parser;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(name = "input parser", about = "Parse an Input file and save its JSON representation")]
|
||||
struct Opt {
|
||||
/// Path to the input file.
|
||||
input_path: PathBuf,
|
||||
|
||||
/// Optional path to the output directory.
|
||||
out_dir_path: Option<PathBuf>,
|
||||
|
||||
/// Whether to print result to STDOUT.
|
||||
#[clap(short, long)]
|
||||
print_stdout: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let opt = Opt::parse();
|
||||
let input_tree = create_session_if_not_set_then(|s| {
|
||||
let input_string = s.source_map.load_file(&opt.input_path).expect("failed to open an input file");
|
||||
|
||||
Handler::with(|handler| {
|
||||
let node_builder = NodeBuilder::default();
|
||||
let input =
|
||||
leo_parser::parse_program_inputs(handler, &node_builder, &input_string.src, input_string.start_pos)?;
|
||||
input.to_json_string()
|
||||
})
|
||||
.map_err(|e| e.to_string())
|
||||
})?;
|
||||
|
||||
if opt.print_stdout {
|
||||
println!("{input_tree}");
|
||||
}
|
||||
|
||||
let out_path = if let Some(out_dir) = opt.out_dir_path {
|
||||
format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
} else {
|
||||
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
};
|
||||
|
||||
fs::write(Path::new(&out_path), input_tree).expect("failed to write output");
|
||||
|
||||
Ok(())
|
||||
}
|
@ -31,7 +31,7 @@ pub(crate) use tokenizer::*;
|
||||
pub mod parser;
|
||||
pub use parser::*;
|
||||
|
||||
use leo_ast::{input::InputData, Ast, NodeBuilder, ProgramInput};
|
||||
use leo_ast::{Ast, NodeBuilder};
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
|
||||
#[cfg(test)]
|
||||
@ -41,16 +41,3 @@ mod test;
|
||||
pub fn parse_ast(handler: &Handler, node_builder: &NodeBuilder, source: &str, start_pos: BytePos) -> Result<Ast> {
|
||||
Ok(Ast::new(parser::parse(handler, node_builder, source, start_pos)?))
|
||||
}
|
||||
|
||||
/// Parses program inputs from the input file path
|
||||
pub fn parse_program_inputs(
|
||||
handler: &Handler,
|
||||
node_builder: &NodeBuilder,
|
||||
input_string: &str,
|
||||
start_pos: BytePos,
|
||||
) -> Result<InputData> {
|
||||
let program_input: ProgramInput =
|
||||
parser::parse_input(handler, node_builder, input_string, start_pos)?.try_into()?;
|
||||
|
||||
Ok(InputData { program_input })
|
||||
}
|
||||
|
@ -39,8 +39,6 @@ pub(crate) struct ParserContext<'a> {
|
||||
pub(crate) prev_token: SpannedToken,
|
||||
/// true if parsing an expression for if and loop statements -- means struct inits are not legal
|
||||
pub(crate) disallow_struct_construction: bool,
|
||||
/// true if parsing an identifier inside an input file.
|
||||
pub(crate) allow_identifier_underscores: bool,
|
||||
}
|
||||
|
||||
/// Dummy span used to appease borrow checker.
|
||||
@ -59,7 +57,6 @@ impl<'a> ParserContext<'a> {
|
||||
handler,
|
||||
node_builder,
|
||||
disallow_struct_construction: false,
|
||||
allow_identifier_underscores: false,
|
||||
prev_token: token.clone(),
|
||||
token,
|
||||
tokens,
|
||||
|
@ -17,7 +17,7 @@
|
||||
use super::*;
|
||||
use leo_errors::{ParserError, Result};
|
||||
|
||||
use leo_span::{sym, Symbol};
|
||||
use leo_span::sym;
|
||||
use snarkvm::console::{account::Address, network::Testnet3};
|
||||
|
||||
const INT_TYPES: &[Token] = &[
|
||||
@ -429,6 +429,25 @@ impl ParserContext<'_> {
|
||||
self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
|
||||
}
|
||||
|
||||
// Parses an externa function call `credits.aleo/transfer()` or `board.leo/make_move()`
|
||||
fn parse_external_call(&mut self, expr: Expression) -> Result<Expression> {
|
||||
// Eat an external function call.
|
||||
self.eat(&Token::Div); // todo: Make `/` a more general token.
|
||||
|
||||
// Parse function name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
||||
// Parse the function call.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
Ok(Expression::Call(CallExpression {
|
||||
span: expr.span() + span,
|
||||
function: Box::new(Expression::Identifier(name)),
|
||||
external: Some(Box::new(expr)),
|
||||
arguments,
|
||||
id: self.node_builder.next_id(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent an
|
||||
/// array access, struct member access, function call, or static function call expression.
|
||||
///
|
||||
@ -450,21 +469,9 @@ impl ParserContext<'_> {
|
||||
id: self.node_builder.next_id(),
|
||||
}))
|
||||
} else if self.eat(&Token::Leo) {
|
||||
// Eat an external function call.
|
||||
self.eat(&Token::Div); // todo: Make `/` a more general token.
|
||||
|
||||
// Parse function name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
||||
// Parse the function call.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
expr = Expression::Call(CallExpression {
|
||||
span: expr.span() + span,
|
||||
function: Box::new(Expression::Identifier(name)),
|
||||
external: Some(Box::new(expr)),
|
||||
arguments,
|
||||
id: self.node_builder.next_id(),
|
||||
});
|
||||
return Err(ParserError::only_aleo_external_calls(expr.span()).into());
|
||||
} else if self.eat(&Token::Aleo) {
|
||||
expr = self.parse_external_call(expr)?;
|
||||
} else {
|
||||
// Parse identifier name.
|
||||
let name = self.expect_identifier()?;
|
||||
@ -616,16 +623,7 @@ impl ParserContext<'_> {
|
||||
}
|
||||
|
||||
fn parse_struct_member(&mut self) -> Result<StructVariableInitializer> {
|
||||
let identifier = if self.allow_identifier_underscores && self.eat(&Token::Underscore) {
|
||||
// Allow `_nonce` for struct records.
|
||||
let identifier_without_underscore = self.expect_identifier()?;
|
||||
Identifier::new(
|
||||
Symbol::intern(&format!("_{}", identifier_without_underscore.name)),
|
||||
self.node_builder.next_id(),
|
||||
)
|
||||
} else {
|
||||
self.expect_identifier()?
|
||||
};
|
||||
let identifier = self.expect_identifier()?;
|
||||
|
||||
let (expression, span) = if self.eat(&Token::Colon) {
|
||||
// Parse individual struct variable declarations.
|
||||
|
@ -15,11 +15,8 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use crate::parse_ast;
|
||||
use leo_errors::{CompilerError, ParserError, Result};
|
||||
use leo_span::{source_map::FileName, symbol::with_session_globals};
|
||||
|
||||
use std::fs;
|
||||
use leo_errors::{ParserError, Result};
|
||||
|
||||
impl ParserContext<'_> {
|
||||
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
|
||||
@ -56,7 +53,7 @@ impl ParserContext<'_> {
|
||||
return Err(ParserError::missing_program_scope(self.token.span).into());
|
||||
}
|
||||
|
||||
Ok(Program { imports, program_scopes })
|
||||
Ok(Program { imports, stubs: IndexMap::new(), program_scopes })
|
||||
}
|
||||
|
||||
fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError {
|
||||
@ -76,45 +73,21 @@ impl ParserContext<'_> {
|
||||
// Parse `foo`.
|
||||
let import_name = self.expect_identifier()?;
|
||||
|
||||
// Parse `.leo`.
|
||||
// Parse `.aleo`.
|
||||
self.expect(&Token::Dot)?;
|
||||
if !self.eat(&Token::Leo) {
|
||||
// Throw error for non-leo files.
|
||||
return Err(ParserError::leo_imports_only(self.token.span).into());
|
||||
|
||||
if !self.eat(&Token::Aleo) {
|
||||
// Throw error for non-aleo files.
|
||||
return Err(ParserError::invalid_network(self.token.span).into());
|
||||
}
|
||||
|
||||
let end = self.expect(&Token::Semicolon)?;
|
||||
|
||||
// Tokenize and parse import file.
|
||||
// Todo: move this to a different module.
|
||||
let mut import_file_path =
|
||||
std::env::current_dir().map_err(|err| CompilerError::cannot_open_cwd(err, self.token.span))?;
|
||||
import_file_path.push("imports");
|
||||
import_file_path.push(format!("{}.leo", import_name.name));
|
||||
|
||||
// Throw an error if the import file doesn't exist.
|
||||
if !import_file_path.exists() {
|
||||
return Err(CompilerError::import_not_found(import_file_path.display(), self.prev_token.span).into());
|
||||
}
|
||||
|
||||
// Read the import file into string.
|
||||
// Todo: protect against cyclic imports.
|
||||
let program_string =
|
||||
fs::read_to_string(&import_file_path).map_err(|e| CompilerError::file_read_error(&import_file_path, e))?;
|
||||
|
||||
// Create import file name.
|
||||
let name: FileName = FileName::Real(import_file_path);
|
||||
|
||||
// Register the source (`program_string`) in the source map.
|
||||
let prg_sf = with_session_globals(|s| s.source_map.new_source(&program_string, name));
|
||||
|
||||
// Use the parser to construct the imported abstract syntax tree (ast).
|
||||
let program_ast = parse_ast(self.handler, self.node_builder, &prg_sf.src, prg_sf.start_pos)?;
|
||||
|
||||
Ok((import_name.name, (program_ast.into_repr(), start + end)))
|
||||
// Return the import name and the span.
|
||||
Ok((import_name.name, (Program::default(), start + end)))
|
||||
}
|
||||
|
||||
/// Parsers a program scope `program foo.aleo { ... }`.
|
||||
/// Parses a program scope `program foo.aleo { ... }`.
|
||||
fn parse_program_scope(&mut self) -> Result<ProgramScope> {
|
||||
// Parse `program` keyword.
|
||||
let start = self.expect(&Token::Program)?;
|
||||
@ -124,15 +97,13 @@ impl ParserContext<'_> {
|
||||
|
||||
// Parse the program network.
|
||||
self.expect(&Token::Dot)?;
|
||||
let network = self.expect_identifier()?;
|
||||
|
||||
// Otherwise throw parser error
|
||||
self.expect(&Token::Aleo).map_err(|_| ParserError::invalid_network(self.token.span))?;
|
||||
|
||||
// Construct the program id.
|
||||
let program_id = ProgramId { name, network };
|
||||
|
||||
// Check that the program network is valid.
|
||||
if network.name != sym::aleo {
|
||||
return Err(ParserError::invalid_network(network.span).into());
|
||||
}
|
||||
let program_id =
|
||||
ProgramId { name, network: Identifier::new(Symbol::intern("aleo"), self.node_builder.next_id()) };
|
||||
|
||||
// Parse `{`.
|
||||
self.expect(&Token::LeftCurly)?;
|
||||
@ -235,6 +206,13 @@ impl ParserContext<'_> {
|
||||
pub(super) fn parse_struct(&mut self) -> Result<(Symbol, Struct)> {
|
||||
let is_record = matches!(&self.token.token, Token::Record);
|
||||
let start = self.expect_any(&[Token::Struct, Token::Record])?;
|
||||
|
||||
// Check if using external type
|
||||
let file_type = self.look_ahead(1, |t| &t.token);
|
||||
if self.token.token == Token::Dot && (file_type == &Token::Aleo) {
|
||||
return Err(ParserError::cannot_declare_external_struct(self.token.span).into());
|
||||
}
|
||||
|
||||
let struct_name = self.expect_identifier()?;
|
||||
|
||||
self.expect(&Token::LeftCurly)?;
|
||||
@ -302,9 +280,9 @@ impl ParserContext<'_> {
|
||||
let external = self.expect_identifier()?;
|
||||
let mut span = name.span + external.span;
|
||||
|
||||
// Parse `.leo/`.
|
||||
// Parse `.leo/` or `.aleo/`.
|
||||
self.eat(&Token::Dot);
|
||||
self.eat(&Token::Leo);
|
||||
self.eat_any(&[Token::Leo, Token::Aleo]);
|
||||
self.eat(&Token::Div);
|
||||
|
||||
// Parse record name.
|
||||
@ -349,9 +327,9 @@ impl ParserContext<'_> {
|
||||
let external = self.expect_identifier()?;
|
||||
let mut span = external.span;
|
||||
|
||||
// Parse `.leo/`.
|
||||
// Parse `.leo/` or `.aleo/`.
|
||||
self.eat(&Token::Dot);
|
||||
self.eat(&Token::Leo);
|
||||
self.eat_any(&[Token::Leo, Token::Aleo]);
|
||||
self.eat(&Token::Div);
|
||||
|
||||
// Parse record name.
|
||||
@ -374,7 +352,7 @@ impl ParserContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_is_external(&self) -> bool {
|
||||
pub fn peek_is_external(&self) -> bool {
|
||||
matches!((&self.token.token, self.look_ahead(1, |t| &t.token)), (Token::Identifier(_), Token::Dot))
|
||||
}
|
||||
|
||||
@ -433,8 +411,15 @@ impl ParserContext<'_> {
|
||||
}
|
||||
};
|
||||
|
||||
// Parse the function body.
|
||||
let block = self.parse_block()?;
|
||||
// Parse the function body. Allow empty blocks. `fn foo(a:u8);`
|
||||
let (_has_empty_block, block) = match &self.token.token {
|
||||
Token::LeftCurly => (false, self.parse_block()?),
|
||||
Token::Semicolon => {
|
||||
let semicolon = self.expect(&Token::Semicolon)?;
|
||||
(true, Block { statements: Vec::new(), span: semicolon, id: self.node_builder.next_id() })
|
||||
}
|
||||
_ => self.unexpected("block or semicolon")?,
|
||||
};
|
||||
|
||||
// Parse the `finalize` block if it exists.
|
||||
let finalize = match self.eat(&Token::Finalize) {
|
||||
|
@ -1,76 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
use leo_errors::{ParserError, Result};
|
||||
|
||||
impl ParserContext<'_> {
|
||||
/// Returns a [`ParsedInputFile`] struct filled with the data acquired in the file.
|
||||
pub(crate) fn parse_input_file(&mut self) -> Result<InputAst> {
|
||||
// Allow underscores in identifiers for input record declarations.
|
||||
self.allow_identifier_underscores = true;
|
||||
let mut sections = Vec::new();
|
||||
|
||||
while self.has_next() {
|
||||
if self.check(&Token::LeftSquare) {
|
||||
sections.push(self.parse_section()?);
|
||||
} else {
|
||||
return Err(ParserError::unexpected_token(self.token.token.clone(), self.token.span).into());
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow underscores in identifiers outside of input files.
|
||||
self.allow_identifier_underscores = false;
|
||||
|
||||
Ok(InputAst { sections })
|
||||
}
|
||||
|
||||
/// Parses particular section in the Input or State file.
|
||||
/// `
|
||||
/// [<identifier>]
|
||||
/// <...definition>
|
||||
/// `
|
||||
/// Returns [`Section`].
|
||||
fn parse_section(&mut self) -> Result<Section> {
|
||||
self.expect(&Token::LeftSquare)?;
|
||||
let section = self.expect_identifier()?;
|
||||
self.expect(&Token::RightSquare)?;
|
||||
|
||||
let mut definitions = Vec::new();
|
||||
while let Token::Constant | Token::Public | Token::Identifier(_) = self.token.token {
|
||||
definitions.push(self.parse_input_definition()?);
|
||||
}
|
||||
|
||||
Ok(Section { name: section.name, span: section.span, definitions })
|
||||
}
|
||||
|
||||
/// Parses a single parameter definition:
|
||||
/// `<identifier> : <type> = <expression>;`
|
||||
/// Returns [`Definition`].
|
||||
fn parse_input_definition(&mut self) -> Result<Definition> {
|
||||
let mode = self.parse_mode()?;
|
||||
|
||||
let name = self.expect_identifier()?;
|
||||
self.expect(&Token::Colon)?;
|
||||
let (type_, span) = self.parse_type()?;
|
||||
self.expect(&Token::Assign)?;
|
||||
let value = self.parse_unary_expression()?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
|
||||
Ok(Definition { mode, name, type_, value, span })
|
||||
}
|
||||
}
|
@ -34,7 +34,6 @@ pub(super) use context::ParserContext;
|
||||
|
||||
mod expression;
|
||||
mod file;
|
||||
mod input;
|
||||
mod statement;
|
||||
pub(super) mod type_;
|
||||
|
||||
@ -44,15 +43,3 @@ pub fn parse(handler: &Handler, node_builder: &NodeBuilder, source: &str, start_
|
||||
|
||||
tokens.parse_program()
|
||||
}
|
||||
|
||||
/// Parses an input file at the given file `path` and `source` code text.
|
||||
pub fn parse_input(
|
||||
handler: &Handler,
|
||||
node_builder: &NodeBuilder,
|
||||
source: &str,
|
||||
start_pos: BytePos,
|
||||
) -> Result<InputAst> {
|
||||
let mut tokens = ParserContext::new(handler, node_builder, crate::tokenize(source, start_pos)?);
|
||||
|
||||
tokens.parse_input_file()
|
||||
}
|
||||
|
@ -79,6 +79,28 @@ impl ParserContext<'_> {
|
||||
/// Also returns the span of the parsed token.
|
||||
pub fn parse_type(&mut self) -> Result<(Type, Span)> {
|
||||
if let Some(ident) = self.eat_identifier() {
|
||||
// Check if using external type
|
||||
let file_type = self.look_ahead(1, |t| &t.token);
|
||||
if self.token.token == Token::Dot && (file_type == &Token::Aleo) {
|
||||
// Only allow `.aleo` as the network identifier
|
||||
if file_type == &Token::Leo {
|
||||
return Err(ParserError::invalid_network(self.token.span).into());
|
||||
}
|
||||
|
||||
// Parse `.aleo/`
|
||||
self.expect(&Token::Dot)?;
|
||||
self.expect(&Token::Aleo)?;
|
||||
self.expect(&Token::Div)?;
|
||||
|
||||
// Parse the record name
|
||||
if let Some(record_name) = self.eat_identifier() {
|
||||
// Return the external type
|
||||
return Ok((Type::Identifier(record_name), ident.span + record_name.span));
|
||||
} else {
|
||||
return Err(ParserError::invalid_external_type(self.token.span).into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok((Type::Identifier(ident), ident.span))
|
||||
} else if self.token.token == Token::LeftSquare {
|
||||
// Parse the left bracket.
|
||||
|
@ -202,18 +202,6 @@ impl Namespace for SerializeNamespace {
|
||||
}
|
||||
}
|
||||
|
||||
struct InputNamespace;
|
||||
|
||||
impl Namespace for InputNamespace {
|
||||
fn parse_type(&self) -> ParseType {
|
||||
ParseType::Whole
|
||||
}
|
||||
|
||||
fn run_test(&self, test: Test) -> Result<Value, String> {
|
||||
create_session_if_not_set_then(|s| with_handler(tokenize(test, s)?, |p| p.parse_input_file()).map(yaml_or_fail))
|
||||
}
|
||||
}
|
||||
|
||||
struct TestRunner;
|
||||
|
||||
impl Runner for TestRunner {
|
||||
@ -223,7 +211,6 @@ impl Runner for TestRunner {
|
||||
"ParseExpression" => Box::new(ParseExpressionNamespace),
|
||||
"ParseStatement" => Box::new(ParseStatementNamespace),
|
||||
"Serialize" => Box::new(SerializeNamespace),
|
||||
"Input" => Box::new(InputNamespace),
|
||||
"Token" => Box::new(TokenNamespace),
|
||||
_ => return None,
|
||||
})
|
||||
|
@ -379,6 +379,7 @@ impl Token {
|
||||
match &*identifier {
|
||||
x if x.starts_with("aleo1") => Token::AddressLit(identifier),
|
||||
"address" => Token::Address,
|
||||
"aleo" => Token::Aleo,
|
||||
"as" => Token::As,
|
||||
"assert" => Token::Assert,
|
||||
"assert_eq" => Token::AssertEq,
|
||||
|
@ -138,6 +138,7 @@ pub enum Token {
|
||||
Transition,
|
||||
|
||||
// Meta Tokens
|
||||
Aleo,
|
||||
Block,
|
||||
Eof,
|
||||
Leo,
|
||||
@ -149,6 +150,7 @@ pub enum Token {
|
||||
/// because true and false are also boolean literals, which are different tokens from keywords.
|
||||
pub const KEYWORD_TOKENS: &[Token] = &[
|
||||
Token::Address,
|
||||
Token::Aleo,
|
||||
Token::As,
|
||||
Token::Assert,
|
||||
Token::AssertEq,
|
||||
@ -205,6 +207,7 @@ impl Token {
|
||||
pub fn keyword_to_symbol(&self) -> Option<Symbol> {
|
||||
Some(match self {
|
||||
Token::Address => sym::address,
|
||||
Token::Aleo => sym::aleo,
|
||||
Token::As => sym::As,
|
||||
Token::Assert => sym::assert,
|
||||
Token::AssertEq => sym::assert_eq,
|
||||
@ -341,6 +344,7 @@ impl fmt::Display for Token {
|
||||
U128 => write!(f, "u128"),
|
||||
Record => write!(f, "record"),
|
||||
|
||||
Aleo => write!(f, "aleo"),
|
||||
As => write!(f, "as"),
|
||||
Assert => write!(f, "assert"),
|
||||
AssertEq => write!(f, "assert_eq"),
|
||||
|
@ -30,6 +30,7 @@ use leo_ast::{
|
||||
Identifier,
|
||||
Literal,
|
||||
MemberAccess,
|
||||
ProgramScope,
|
||||
StructExpression,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
@ -518,7 +519,6 @@ impl<'a> CodeGenerator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Cleanup
|
||||
fn visit_call(&mut self, input: &'a CallExpression) -> (String, String) {
|
||||
let (mut call_instruction, has_finalize) = match &input.external {
|
||||
Some(external) => {
|
||||
@ -528,7 +528,9 @@ impl<'a> CodeGenerator<'a> {
|
||||
Expression::Identifier(identifier) => identifier.name,
|
||||
_ => unreachable!("Parsing guarantees that a program name is always an identifier."),
|
||||
};
|
||||
let stub_scope: ProgramScope;
|
||||
// Lookup the imported program scope.
|
||||
// TODO: Needs refactor. All imports are stubs now.
|
||||
let imported_program_scope = match self
|
||||
.program
|
||||
.imports
|
||||
@ -536,7 +538,14 @@ impl<'a> CodeGenerator<'a> {
|
||||
.and_then(|(program, _)| program.program_scopes.get(&program_name))
|
||||
{
|
||||
Some(program) => program,
|
||||
None => unreachable!("Type checking guarantees that imported programs are well defined."),
|
||||
None => {
|
||||
if let Some(stub_program) = self.program.stubs.get(&program_name) {
|
||||
stub_scope = ProgramScope::from(stub_program.clone());
|
||||
&stub_scope
|
||||
} else {
|
||||
unreachable!("Type checking guarantees that imported and stub programs are well defined.")
|
||||
}
|
||||
}
|
||||
};
|
||||
// Check if the external function has a finalize block.
|
||||
let function_name = match *input.function {
|
||||
|
@ -28,19 +28,10 @@ impl<'a> CodeGenerator<'a> {
|
||||
// Accumulate instructions into a program string.
|
||||
let mut program_string = String::new();
|
||||
|
||||
if !input.imports.is_empty() {
|
||||
// Visit each import statement and produce a Aleo import instruction.
|
||||
program_string.push_str(
|
||||
&input
|
||||
.imports
|
||||
.iter()
|
||||
.map(|(identifier, (imported_program, _))| self.visit_import(identifier, imported_program))
|
||||
.join("\n"),
|
||||
);
|
||||
|
||||
// Newline separator.
|
||||
program_string.push('\n');
|
||||
}
|
||||
// Print out the dependencies of the program. Already arranged in post order by Retriever module.
|
||||
input.stubs.iter().for_each(|(program_name, _)| {
|
||||
program_string.push_str(&format!("import {}.aleo;\n", program_name));
|
||||
});
|
||||
|
||||
// Retrieve the program scope.
|
||||
// Note that type checking guarantees that there is exactly one program scope.
|
||||
@ -109,15 +100,6 @@ impl<'a> CodeGenerator<'a> {
|
||||
program_string
|
||||
}
|
||||
|
||||
fn visit_import(&mut self, import_name: &'a Symbol, import_program: &'a Program) -> String {
|
||||
// Load symbols into composite mapping.
|
||||
let _import_program_string = self.visit_program(import_program);
|
||||
// todo: We do not need the import program string because we generate instructions for imports separately during leo build.
|
||||
|
||||
// Generate string for import statement.
|
||||
format!("import {import_name}.aleo;")
|
||||
}
|
||||
|
||||
fn visit_struct_or_record(&mut self, struct_: &'a Struct) -> String {
|
||||
if struct_.is_record { self.visit_record(struct_) } else { self.visit_struct(struct_) }
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub use variable_symbol::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use leo_ast::{normalize_json_value, remove_key_from_json, Function, Struct};
|
||||
use leo_errors::{AstError, Result};
|
||||
use leo_errors::{AstError, LeoMessageCode, Result};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@ -89,11 +89,46 @@ impl SymbolTable {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if the struct is a duplicate of the existing struct.
|
||||
/// This is used to allow redefinitions of external structs.
|
||||
pub fn check_duplicate_struct(&self, old: &Struct, new: &Struct) -> bool {
|
||||
if old.members.len() != new.members.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (old_member, new_member) in old.members.iter().zip(new.members.iter()) {
|
||||
if old_member.identifier.name != new_member.identifier.name {
|
||||
return false;
|
||||
}
|
||||
if old_member.type_ != new_member.type_ {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Inserts a struct into the symbol table.
|
||||
pub fn insert_struct(&mut self, symbol: Symbol, insert: &Struct) -> Result<()> {
|
||||
self.check_shadowing(symbol, insert.span)?;
|
||||
self.structs.insert(symbol, insert.clone());
|
||||
Ok(())
|
||||
match self.check_shadowing(symbol, insert.span) {
|
||||
Ok(_) => {
|
||||
self.structs.insert(symbol, insert.clone());
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
if e.error_code() == AstError::shadowed_struct(symbol, insert.span).error_code() {
|
||||
if self.check_duplicate_struct(
|
||||
self.structs.get(&symbol).expect("Must be in symbol table since struct already referenced"),
|
||||
insert,
|
||||
) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AstError::redefining_external_struct(symbol).into())
|
||||
}
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a variable into the symbol table.
|
||||
|
@ -34,6 +34,21 @@ impl ProgramReconstructor for Unroller<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
// Don't need to reconstruct anything, just need to add child scopes for constant propagation table
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub) -> FunctionStub {
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
let previous_function_index = self.enter_scope(function_index);
|
||||
|
||||
// Exit the function's scope.
|
||||
self.exit_scope(previous_function_index);
|
||||
|
||||
input
|
||||
}
|
||||
|
||||
fn reconstruct_function(&mut self, function: Function) -> Function {
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
|
@ -151,6 +151,7 @@ impl ProgramConsumer for StaticSingleAssigner<'_> {
|
||||
.into_iter()
|
||||
.map(|(name, (import, span))| (name, (self.consume_program(import), span)))
|
||||
.collect(),
|
||||
stubs: input.stubs,
|
||||
program_scopes: input
|
||||
.program_scopes
|
||||
.into_iter()
|
||||
|
@ -72,4 +72,16 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_stub(&mut self, input: &'a Stub) {
|
||||
input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
|
||||
|
||||
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), &Function::from(input.clone())) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{DiGraphError, TypeChecker, VariableSymbol, VariableType};
|
||||
use crate::{DiGraphError, TypeChecker};
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::TypeCheckerError;
|
||||
@ -28,30 +28,80 @@ use std::collections::HashSet;
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_program(&mut self, input: &'a Program) {
|
||||
match self.is_imported {
|
||||
// If the program is imported, then it is not allowed to import any other programs.
|
||||
true => {
|
||||
input.imports.values().for_each(|(_, span)| {
|
||||
self.emit_err(TypeCheckerError::imported_program_cannot_import_program(*span))
|
||||
});
|
||||
}
|
||||
// Otherwise, typecheck the imported programs.
|
||||
false => {
|
||||
// Set `self.is_imported`.
|
||||
let previous_is_imported = core::mem::replace(&mut self.is_imported, true);
|
||||
// Calculate the intersection of the imports specified in the `.leo` file and the dependencies derived from the `program.json` file.
|
||||
|
||||
// Typecheck the imported programs.
|
||||
input.imports.values().for_each(|import| self.visit_import(&import.0));
|
||||
|
||||
// Set `self.is_imported` to its previous state.
|
||||
self.is_imported = previous_is_imported;
|
||||
// Typecheck the program's stubs.
|
||||
input.stubs.iter().for_each(|(symbol, stub)| {
|
||||
if symbol != &stub.stub_id.name.name {
|
||||
self.emit_err(TypeCheckerError::stub_name_mismatch(
|
||||
symbol,
|
||||
stub.stub_id.name,
|
||||
stub.stub_id.network.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
self.visit_stub(stub)
|
||||
});
|
||||
|
||||
// Typecheck the program scopes.
|
||||
input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
|
||||
}
|
||||
|
||||
fn visit_stub(&mut self, input: &'a Stub) {
|
||||
// Cannot have constant declarations in stubs.
|
||||
if !input.consts.is_empty() {
|
||||
self.emit_err(TypeCheckerError::stubs_cannot_have_const_declarations(input.consts.get(0).unwrap().1.span));
|
||||
}
|
||||
|
||||
// Typecheck the program's structs.
|
||||
input.structs.iter().for_each(|(_, function)| self.visit_struct_stub(function));
|
||||
|
||||
// Typecheck the program's functions.
|
||||
input.functions.iter().for_each(|(_, function)| self.visit_function_stub(function));
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
|
||||
// Must not be an inline function
|
||||
if input.variant == Variant::Inline {
|
||||
self.emit_err(TypeCheckerError::stub_functions_must_not_be_inlines(input.span));
|
||||
}
|
||||
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
self.enter_scope(function_index);
|
||||
|
||||
// Create a new child scope for the function's parameters and body.
|
||||
let scope_index = self.create_child_scope();
|
||||
|
||||
// Query helper function to type check function parameters and outputs.
|
||||
self.check_function_signature(&Function::from(input.clone()));
|
||||
|
||||
// Exit the scope for the function's parameters and body.
|
||||
self.exit_scope(scope_index);
|
||||
|
||||
// Check that the finalize scope is valid
|
||||
if input.finalize_stub.is_some() {
|
||||
// Create a new child scope for the finalize block.
|
||||
let scope_index = self.create_child_scope();
|
||||
|
||||
// Check the finalize signature.
|
||||
let function = &Function::from(input.clone());
|
||||
self.check_finalize_signature(function.finalize.as_ref().unwrap(), function);
|
||||
|
||||
// Exit the scope for the finalize block.
|
||||
self.exit_scope(scope_index);
|
||||
}
|
||||
|
||||
// Exit the function's scope.
|
||||
self.exit_scope(function_index);
|
||||
}
|
||||
|
||||
fn visit_struct_stub(&mut self, input: &'a Struct) {
|
||||
self.visit_struct(input);
|
||||
}
|
||||
|
||||
fn visit_program_scope(&mut self, input: &'a ProgramScope) {
|
||||
// Typecheck each const definition, and append to symbol table.
|
||||
input.consts.iter().for_each(|(_, c)| self.visit_const(c));
|
||||
@ -232,77 +282,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
// Create a new child scope for the function's parameters and body.
|
||||
let scope_index = self.create_child_scope();
|
||||
|
||||
// Type check the function's parameters.
|
||||
function.input.iter().for_each(|input_var| {
|
||||
// Check that the type of input parameter is defined.
|
||||
self.assert_type_is_valid(&input_var.type_(), input_var.span());
|
||||
// Check that the type of the input parameter is not a tuple.
|
||||
if matches!(input_var.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input_var.span()))
|
||||
}
|
||||
|
||||
// Note that this unwrap is safe since we assign to `self.variant` above.
|
||||
match self.variant.unwrap() {
|
||||
// If the function is a transition function, then check that the parameter mode is not a constant.
|
||||
Variant::Transition if input_var.mode() == Mode::Constant => {
|
||||
self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input_var.span()))
|
||||
}
|
||||
// If the function is not a transition function, then check that the parameters do not have an associated mode.
|
||||
Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => {
|
||||
self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()))
|
||||
}
|
||||
_ => {} // Do nothing.
|
||||
}
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
})
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Type check the function's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to check that `output_type` is defined.
|
||||
function.output.iter().for_each(|output| {
|
||||
match output {
|
||||
Output::External(external) => {
|
||||
// If the function is not a transition function, then it cannot output a record.
|
||||
// Note that an external output must always be a record.
|
||||
if !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_output_record(external.span()));
|
||||
}
|
||||
// Otherwise, do not type check external record function outputs.
|
||||
// TODO: Verify that this is not needed when the import system is updated.
|
||||
}
|
||||
Output::Internal(function_output) => {
|
||||
// Check that the type of output is defined.
|
||||
if self.assert_type_is_valid(&function_output.type_, function_output.span) {
|
||||
// If the function is not a transition function, then it cannot output a record.
|
||||
if let Type::Identifier(identifier) = function_output.type_ {
|
||||
if !matches!(function.variant, Variant::Transition)
|
||||
&& self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record
|
||||
{
|
||||
self.emit_err(TypeCheckerError::function_cannot_output_record(function_output.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that the type of the output is not a tuple. This is necessary to forbid nested tuples.
|
||||
if matches!(&function_output.type_, Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
|
||||
}
|
||||
// Check that the mode of the output is valid.
|
||||
// For functions, only public and private outputs are allowed
|
||||
if function_output.mode == Mode::Constant {
|
||||
self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Query helper function to type check function parameters and outputs.
|
||||
self.check_function_signature(function);
|
||||
|
||||
self.visit_block(&function.block);
|
||||
|
||||
@ -324,90 +305,16 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
self.is_finalize = true;
|
||||
// The function's finalize block does not have a return statement.
|
||||
self.has_return = false;
|
||||
// The function;s finalize block does not have a finalize statement.
|
||||
// The function's finalize block does not have a finalize statement.
|
||||
self.has_finalize = false;
|
||||
|
||||
// Check that the function is a transition function.
|
||||
if !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize(finalize.span));
|
||||
}
|
||||
|
||||
// Check that the name of the finalize block matches the function name.
|
||||
if function.identifier.name != finalize.identifier.name {
|
||||
self.emit_err(TypeCheckerError::finalize_name_mismatch(
|
||||
function.identifier.name,
|
||||
finalize.identifier.name,
|
||||
finalize.span,
|
||||
));
|
||||
}
|
||||
|
||||
// Create a new child scope for the finalize block.
|
||||
let scope_index = self.create_child_scope();
|
||||
|
||||
finalize.input.iter().for_each(|input_var| {
|
||||
// Check that the type of input parameter is defined.
|
||||
if self.assert_type_is_valid(&input_var.type_(), input_var.span()) {
|
||||
// Check that the input parameter is not a tuple.
|
||||
if matches!(input_var.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_take_tuple_as_input(input_var.span()))
|
||||
}
|
||||
// Check that the input parameter is not a record.
|
||||
if let Type::Identifier(identifier) = input_var.type_() {
|
||||
// Note that this unwrap is safe, as the type is defined.
|
||||
if self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_take_record_as_input(input_var.span()))
|
||||
}
|
||||
}
|
||||
// Check that the input parameter is not constant or private.
|
||||
if input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private {
|
||||
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
|
||||
}
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
})
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Check the finalize signature.
|
||||
self.check_finalize_signature(finalize, function);
|
||||
|
||||
// Check that the finalize block's return type is a unit type.
|
||||
// Note: This is a temporary restriction to be compatible with the current version of snarkVM.
|
||||
// Note: This restriction may be lifted in the future.
|
||||
// Note: This check is still compatible with the other checks below.
|
||||
if finalize.output_type != Type::Unit {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_return_value(finalize.span));
|
||||
}
|
||||
|
||||
// Type check the finalize block's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to guarantee that the `output_type` is defined.
|
||||
finalize.output.iter().for_each(|output_type| {
|
||||
// Check that the type of output is defined.
|
||||
if self.assert_type_is_valid(&output_type.type_(), output_type.span()) {
|
||||
// Check that the output is not a tuple. This is necessary to forbid nested tuples.
|
||||
if matches!(&output_type.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(output_type.span()))
|
||||
}
|
||||
// Check that the output is not a record.
|
||||
if let Type::Identifier(identifier) = output_type.type_() {
|
||||
// Note that this unwrap is safe, as the type is defined.
|
||||
if self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_output_record(output_type.span()))
|
||||
}
|
||||
}
|
||||
// Check that the mode of the output is valid.
|
||||
// Note that a finalize block can have only public outputs.
|
||||
if matches!(output_type.mode(), Mode::Constant | Mode::Private) {
|
||||
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(output_type.span()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Remove if this restriction is relaxed at Aleo instructions level.
|
||||
// TODO: Remove if this restriction is relaxed at Aleo instructions level
|
||||
// Check that the finalize block is not empty.
|
||||
if finalize.block.statements.is_empty() {
|
||||
self.emit_err(TypeCheckerError::finalize_block_must_not_be_empty(finalize.span));
|
||||
@ -416,9 +323,6 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
// Type check the finalize block.
|
||||
self.visit_block(&finalize.block);
|
||||
|
||||
// Check that the return type is defined. Note that the component types are already checked.
|
||||
self.assert_type_is_valid(&finalize.output_type, finalize.span);
|
||||
|
||||
// If the function has a return type, then check that it has a return.
|
||||
if finalize.output_type != Type::Unit && !self.has_return {
|
||||
self.emit_err(TypeCheckerError::missing_return(finalize.span));
|
||||
|
@ -14,9 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{CallGraph, StructGraph, SymbolTable, TypeTable};
|
||||
use crate::{CallGraph, StructGraph, SymbolTable, TypeTable, VariableSymbol, VariableType};
|
||||
|
||||
use leo_ast::{CoreConstant, CoreFunction, Identifier, IntegerType, MappingType, Node, Type, Variant};
|
||||
use leo_ast::{
|
||||
CoreConstant,
|
||||
CoreFunction,
|
||||
Finalize,
|
||||
Function,
|
||||
Identifier,
|
||||
IntegerType,
|
||||
MappingType,
|
||||
Mode,
|
||||
Node,
|
||||
Output,
|
||||
Type,
|
||||
Variant,
|
||||
};
|
||||
use leo_errors::{emitter::Handler, TypeCheckerError};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
@ -47,8 +60,6 @@ pub struct TypeChecker<'a> {
|
||||
|
||||
/// Whether or not we are currently traversing a finalize block.
|
||||
pub(crate) is_finalize: bool,
|
||||
/// Whether or not we are currently traversing an imported program.
|
||||
pub(crate) is_imported: bool,
|
||||
/// Whether or not we are currently traversing a return statement.
|
||||
pub(crate) is_return: bool,
|
||||
}
|
||||
@ -116,7 +127,6 @@ impl<'a> TypeChecker<'a> {
|
||||
has_return: false,
|
||||
has_finalize: false,
|
||||
is_finalize: false,
|
||||
is_imported: false,
|
||||
is_return: false,
|
||||
}
|
||||
}
|
||||
@ -1130,6 +1140,176 @@ impl<'a> TypeChecker<'a> {
|
||||
pub(crate) fn assert_array_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(|type_| matches!(type_, Type::Array(_)), "array".to_string(), type_, span);
|
||||
}
|
||||
|
||||
/// Helper function to check that the input and output of function are valid
|
||||
pub(crate) fn check_function_signature(&mut self, function: &Function) {
|
||||
self.variant = Some(function.variant);
|
||||
|
||||
// Type check the function's parameters.
|
||||
function.input.iter().for_each(|input_var| {
|
||||
// Check that the type of input parameter is defined.
|
||||
self.assert_type_is_valid(&input_var.type_(), input_var.span());
|
||||
// Check that the type of the input parameter is not a tuple.
|
||||
if matches!(input_var.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input_var.span()))
|
||||
}
|
||||
|
||||
// Note that this unwrap is safe since we assign to `self.variant` above.
|
||||
match self.variant.unwrap() {
|
||||
// If the function is a transition function, then check that the parameter mode is not a constant.
|
||||
Variant::Transition if input_var.mode() == Mode::Constant => {
|
||||
self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input_var.span()))
|
||||
}
|
||||
// If the function is not a transition function, then check that the parameters do not have an associated mode.
|
||||
Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => {
|
||||
self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()))
|
||||
}
|
||||
_ => {} // Do nothing.
|
||||
}
|
||||
|
||||
// If the function is not a transition function, then it cannot have a record as input
|
||||
if let Type::Identifier(identifier) = input_var.type_() {
|
||||
if let Some(val) = self.symbol_table.borrow().lookup_struct(identifier.name) {
|
||||
if val.is_record && !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input_var.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
})
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Type check the function's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to check that `output_type` is defined.
|
||||
function.output.iter().for_each(|output| {
|
||||
match output {
|
||||
Output::External(external) => {
|
||||
// If the function is not a transition function, then it cannot output a record.
|
||||
// Note that an external output must always be a record.
|
||||
if !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(external.span()));
|
||||
}
|
||||
// Otherwise, do not type check external record function outputs.
|
||||
// TODO: Verify that this is not needed when the import system is updated.
|
||||
}
|
||||
Output::Internal(function_output) => {
|
||||
// Check that the type of output is defined.
|
||||
if self.assert_type_is_valid(&function_output.type_, function_output.span) {
|
||||
// If the function is not a transition function, then it cannot output a record.
|
||||
if let Type::Identifier(identifier) = function_output.type_ {
|
||||
if !matches!(function.variant, Variant::Transition)
|
||||
&& self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record
|
||||
{
|
||||
self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(
|
||||
function_output.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that the type of the output is not a tuple. This is necessary to forbid nested tuples.
|
||||
if matches!(&function_output.type_, Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
|
||||
}
|
||||
// Check that the mode of the output is valid.
|
||||
// For functions, only public and private outputs are allowed
|
||||
if function_output.mode == Mode::Constant {
|
||||
self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn check_finalize_signature(&mut self, finalize: &Finalize, function: &Function) {
|
||||
// Check that the function is a transition function.
|
||||
if !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize(finalize.span));
|
||||
}
|
||||
|
||||
// Check that the name of the finalize block matches the function name.
|
||||
if function.identifier.name != finalize.identifier.name {
|
||||
self.emit_err(TypeCheckerError::finalize_name_mismatch(
|
||||
function.identifier.name,
|
||||
finalize.identifier.name,
|
||||
finalize.span,
|
||||
));
|
||||
}
|
||||
|
||||
finalize.input.iter().for_each(|input_var| {
|
||||
// Check that the type of input parameter is defined.
|
||||
if self.assert_type_is_valid(&input_var.type_(), input_var.span()) {
|
||||
// Check that the input parameter is not a tuple.
|
||||
if matches!(input_var.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_take_tuple_as_input(input_var.span()))
|
||||
}
|
||||
// Check that the input parameter is not a record.
|
||||
if let Type::Identifier(identifier) = input_var.type_() {
|
||||
// Note that this unwrap is safe, as the type is defined.
|
||||
if self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_take_record_as_input(input_var.span()))
|
||||
}
|
||||
}
|
||||
// Check that the input parameter is not constant or private.
|
||||
if input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private {
|
||||
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
|
||||
}
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
})
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Check that the finalize block's return type is a unit type.
|
||||
// Note: This is a temporary restriction to be compatible with the current version of snarkVM.
|
||||
// Note: This restriction may be lifted in the future.
|
||||
// Note: This check is still compatible with the other checks below.
|
||||
if finalize.output_type != Type::Unit {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_return_value(finalize.span));
|
||||
}
|
||||
|
||||
// Type check the finalize block's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to guarantee that the `output_type` is defined.
|
||||
finalize.output.iter().for_each(|output_type| {
|
||||
// Check that the type of output is defined.
|
||||
if self.assert_type_is_valid(&output_type.type_(), output_type.span()) {
|
||||
// Check that the output is not a tuple. This is necessary to forbid nested tuples.
|
||||
if matches!(&output_type.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(output_type.span()))
|
||||
}
|
||||
// Check that the output is not a record.
|
||||
if let Type::Identifier(identifier) = output_type.type_() {
|
||||
// Note that this unwrap is safe, as the type is defined.
|
||||
if self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record {
|
||||
self.emit_err(TypeCheckerError::finalize_cannot_output_record(output_type.span()))
|
||||
}
|
||||
}
|
||||
// Check that the mode of the output is valid.
|
||||
// Note that a finalize block can have only public outputs.
|
||||
if matches!(output_type.mode(), Mode::Constant | Mode::Private) {
|
||||
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(output_type.span()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Check that the return type is defined. Note that the component types are already checked.
|
||||
self.assert_type_is_valid(&finalize.output_type, finalize.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn types_to_string(types: &[Type]) -> String {
|
||||
|
@ -29,5 +29,5 @@ version = "0.2.1"
|
||||
version = "1.0.1"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
features = [ "derive", "rc" ]
|
||||
|
@ -268,6 +268,7 @@ symbols! {
|
||||
owner,
|
||||
_nonce,
|
||||
program,
|
||||
stub,
|
||||
block,
|
||||
height,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Summary
|
||||
|
||||
This is an RFC to propose RFC format for Leo language.
|
||||
This is a RFC to propose RFC format for Leo language.
|
||||
|
||||
# Motivation
|
||||
|
||||
@ -12,11 +12,11 @@ This section describes proposed solution.
|
||||
|
||||
## Store RFCs inside Leo repository.
|
||||
|
||||
At early stages it is for better to see changes with the code eliminating the need to keep track of a different repository.
|
||||
At early stages it is better to see changes with the code eliminating the need to keep track of a different repository.
|
||||
|
||||
## Use standard PR mechanics for submitting new RFCs
|
||||
|
||||
New RFCs should be submitted as a PRs into Leo repository. PRs should be correctly labeled for easier search. Yet they should not have number unless PR is accepted by leo maintainers.
|
||||
New RFCs should be submitted as PRs into the Leo repository. PRs should be correctly labeled for easier search. Yet they should not have a number unless the PR is accepted by leo maintainers.
|
||||
|
||||
## Increase approvals count for RFCs
|
||||
|
||||
@ -24,7 +24,7 @@ RFCs may propose changes affecting multiple systems or projects. They also intro
|
||||
|
||||
## Format
|
||||
|
||||
For bootstrapping new requests template is made and placed into RFC folder.
|
||||
For bootstrapping new requests, a template is made and placed into the RFC folder.
|
||||
|
||||
## Number
|
||||
|
||||
|
@ -37,8 +37,11 @@ version = "0.6.1"
|
||||
[dependencies.derivative]
|
||||
version = "2.2.0"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11.22"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.194"
|
||||
version = "1.0.195"
|
||||
features = [ "derive", "rc" ]
|
||||
|
||||
[dependencies.thiserror]
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
## Parser Errors: Error Code Range 370_000 - 370_999
|
||||
|
||||
## State Errors: Error Code Range 371_000 - 371_999
|
||||
|
||||
## AST Errors: Error Code Range 372_000 - 372_999
|
||||
|
||||
## ASG Errors: Error Code Range 373_000 - 373_999
|
||||
|
@ -49,10 +49,6 @@ The errors for the `leo-compiler` crate. Its error codes will range from 6_000-6
|
||||
|
||||
The errors for the `leo-imports` crate. Its error codes will range from 4_000-4_999 and be prefixed with the characters `IMP`.
|
||||
|
||||
### Input
|
||||
|
||||
The errors for the `leo-ast` crate. Its error codes will range from 8_000-8_999 and be prefixed with the characters `INP`.
|
||||
|
||||
### Loop Unrolling
|
||||
|
||||
The errors for loop unrolling in the `leo-passes` crate. Its error codes will range from 9_000-9_999 and be prefixed with the characters `LUN`.
|
||||
@ -70,6 +66,6 @@ The errors for the `leo-parser` crate. Its error codes will range from 0-999 and
|
||||
The errors from SnarkVM that bubble up into Leo in some situations. For right now, they have an exit code of 1.
|
||||
When SnarkVM implements better error codes and messages, we can bubble them up.
|
||||
|
||||
### State
|
||||
### Utils
|
||||
|
||||
The errors for the `leo-state` crate. Its error codes will range from 1_000-1_999 and be prefixed with the characters `STA`.
|
||||
The errors related to dependency retrieval in the `utils` crate. Its error codes will range from 10_000-10_999 and be prefixed with the characters `DEP`.
|
||||
|
@ -145,4 +145,11 @@ create_messages!(
|
||||
msg: format!("failed to convert symbol_table to a json value {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
redefining_external_struct {
|
||||
args: (struct_: impl Display),
|
||||
msg: format!("There are two mismatched definitions of struct `{struct_}`."),
|
||||
help: Some("Duplicate definitions of structs are required to use external structs, but each field's name and type must match exactly.".to_string()),
|
||||
}
|
||||
);
|
||||
|
@ -70,4 +70,11 @@ create_messages!(
|
||||
msg: format!("The program scope name `{program_scope_name}` must match `{file_name}`."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
imported_program_not_found {
|
||||
args: (main_program_name: impl Display, dependency_name: impl Display),
|
||||
msg: format!("`{main_program_name}` imports `{dependency_name}.aleo`, but `{dependency_name}.aleo` is not found in `program.json`."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -1,58 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::create_messages;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
create_messages!(
|
||||
/// InputError enum that represents all the errors for the inputs part of `leo-ast` crate.
|
||||
InputError,
|
||||
code_mask: 1000i32,
|
||||
code_prefix: "INP",
|
||||
|
||||
/// For when declared variable type mismatches actual type.
|
||||
@formatted
|
||||
unexpected_type {
|
||||
args: (expected: impl Display, received: impl Display),
|
||||
msg: format!(
|
||||
"unexpected type, expected: '{expected}', received: '{received}'",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the expression is not allowed in an input file.
|
||||
@formatted
|
||||
illegal_expression {
|
||||
args: (expr: impl Display),
|
||||
msg: format!("expression '{expr}' is not allowed in inputs"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when section name is not an allowed one.
|
||||
@formatted
|
||||
unexpected_section {
|
||||
args: (expected: &[impl Display], received: impl Display),
|
||||
msg: format!(
|
||||
"unexpected section: expected {} -- got '{received}'",
|
||||
expected
|
||||
.iter()
|
||||
.map(|x| format!("'{x}'"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
);
|
@ -33,10 +33,7 @@ pub use self::compiler::*;
|
||||
pub mod flattener;
|
||||
pub use self::flattener::*;
|
||||
|
||||
/// Contains the Input error definitions.
|
||||
pub mod input;
|
||||
pub use self::input::*;
|
||||
|
||||
/// Contains the Loop Unroller error definitions.
|
||||
pub mod loop_unroller;
|
||||
pub use self::loop_unroller::*;
|
||||
|
||||
@ -50,9 +47,12 @@ pub use self::parser::*;
|
||||
|
||||
/// Contains the Type Checker error definitions.
|
||||
pub mod type_checker;
|
||||
|
||||
pub use self::type_checker::*;
|
||||
|
||||
/// Contains the Utils error definitions.
|
||||
pub mod utils;
|
||||
pub use self::utils::*;
|
||||
|
||||
/// The LeoError type that contains all sub error types.
|
||||
/// This allows a unified error type throughout the Leo crates.
|
||||
#[derive(Debug, Error)]
|
||||
@ -66,9 +66,6 @@ pub enum LeoError {
|
||||
/// Represents an Compiler Error in a Leo Error.
|
||||
#[error(transparent)]
|
||||
CompilerError(#[from] CompilerError),
|
||||
/// Represents an Input Error in a Leo Error.
|
||||
#[error(transparent)]
|
||||
InputError(#[from] InputError),
|
||||
/// Represents an Package Error in a Leo Error.
|
||||
#[error(transparent)]
|
||||
PackageError(#[from] PackageError),
|
||||
@ -88,6 +85,9 @@ pub enum LeoError {
|
||||
/// not re-displaying an error.
|
||||
#[error("")]
|
||||
LastErrorCode(i32),
|
||||
/// Represents a Utils Error in a Leo Error
|
||||
#[error(transparent)]
|
||||
UtilError(#[from] UtilError),
|
||||
/// Anyhow errors.
|
||||
#[error(transparent)]
|
||||
Anyhow(#[from] anyhow::Error),
|
||||
@ -102,12 +102,12 @@ impl LeoError {
|
||||
AstError(error) => error.error_code(),
|
||||
CompilerError(error) => error.error_code(),
|
||||
CliError(error) => error.error_code(),
|
||||
InputError(error) => error.error_code(),
|
||||
ParserError(error) => error.error_code(),
|
||||
PackageError(error) => error.error_code(),
|
||||
TypeCheckerError(error) => error.error_code(),
|
||||
LoopUnrollerError(error) => error.error_code(),
|
||||
FlattenError(error) => error.error_code(),
|
||||
UtilError(error) => error.error_code(),
|
||||
LastErrorCode(_) => unreachable!(),
|
||||
Anyhow(_) => unimplemented!(), // todo: implement error codes for snarkvm errors.
|
||||
}
|
||||
@ -121,12 +121,12 @@ impl LeoError {
|
||||
AstError(error) => error.exit_code(),
|
||||
CompilerError(error) => error.exit_code(),
|
||||
CliError(error) => error.exit_code(),
|
||||
InputError(error) => error.exit_code(),
|
||||
ParserError(error) => error.exit_code(),
|
||||
PackageError(error) => error.exit_code(),
|
||||
TypeCheckerError(error) => error.exit_code(),
|
||||
LoopUnrollerError(error) => error.exit_code(),
|
||||
FlattenError(error) => error.exit_code(),
|
||||
UtilError(error) => error.exit_code(),
|
||||
LastErrorCode(code) => *code,
|
||||
Anyhow(_) => unimplemented!(), // todo: implement exit codes for snarkvm errors.
|
||||
}
|
||||
|
@ -264,6 +264,27 @@ create_messages!(
|
||||
help: Some("Create a package by running `leo new`.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_read_manifest {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to read manifest file: {error}"),
|
||||
help: Some("Create a package by running `leo new`.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_write_manifest {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to write manifest file: {error}"),
|
||||
help: Some("Create a package by running `leo new`.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_create_manifest {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to create manifest file: {error}"),
|
||||
help: Some("Create a package by running `leo new`.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_open_aleo_file {
|
||||
args: (error: impl Display),
|
||||
@ -313,4 +334,18 @@ create_messages!(
|
||||
msg: format!("IO error env file from the provided file path - {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_deserialize_manifest_file {
|
||||
args: (path: impl Display, error: impl ErrorArg),
|
||||
msg: format!("Failed to deserialize `program.json` from the provided file path {path} - {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_serialize_manifest_file {
|
||||
args: (path: impl Display, error: impl ErrorArg),
|
||||
msg: format!("Failed to update `program.json` from the provided file path {path} - {error}"),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -215,10 +215,10 @@ create_messages!(
|
||||
}
|
||||
|
||||
@formatted
|
||||
leo_imports_only {
|
||||
leo_and_aleo_imports_only {
|
||||
args: (),
|
||||
msg: "Invalid import call to non-leo file.",
|
||||
help: Some("Only imports of Leo `.leo` files are currently supported.".to_string()),
|
||||
msg: "Invalid import call to non-leo non-aleo file.",
|
||||
help: Some("Only imports of Leo `.leo` and Aleo `.aleo` files are currently supported.".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
@ -252,7 +252,7 @@ create_messages!(
|
||||
@formatted
|
||||
invalid_network {
|
||||
args: (),
|
||||
msg: "Invalid network identifier. The only supported identifier is `aleo`.",
|
||||
msg: "Invalid network identifier. The only supported identifier is `.aleo`.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -298,4 +298,41 @@ create_messages!(
|
||||
msg: format!("An array {kind} must have at least one element."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
invalid_external_type {
|
||||
args: (),
|
||||
msg: format!("Invalid external type."),
|
||||
help: Some("External type should have the form `<program>.aleo/<record>`. For example `bank.aleo/loan`".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
cannot_declare_external_struct {
|
||||
args: (),
|
||||
msg: format!("Cannot declare external struct."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Enforce that cannot use an external type to do anything except input/output of function
|
||||
@formatted
|
||||
external_type_cannot_be_used_inside_function {
|
||||
args: (program: impl Display, file_type: impl Display),
|
||||
msg: format!("External types cannot be used inside function (only as input/output types) -- found exported type from '{program}.{file_type}'."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Enforce that cannot use import in program scope
|
||||
@formatted
|
||||
cannot_import_inside_program_body {
|
||||
args: (),
|
||||
msg: format!("Cannot use import inside program body."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
only_aleo_external_calls {
|
||||
args: (),
|
||||
msg: format!("Only external calls to `.aleo` programs are supported."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/// This module contains the State error definitions.
|
||||
pub mod state_errors;
|
||||
pub use self::state_errors::*;
|
@ -454,7 +454,7 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
// TODO: Consider chainging this to a warning.
|
||||
// TODO: Consider changing this to a warning.
|
||||
|
||||
@formatted
|
||||
assign_unit_expression_to_variable {
|
||||
@ -534,9 +534,9 @@ create_messages!(
|
||||
}
|
||||
|
||||
@formatted
|
||||
function_cannot_output_record {
|
||||
function_cannot_input_or_output_a_record {
|
||||
args: (),
|
||||
msg: format!("A `function` cannot output a record."),
|
||||
msg: format!("A `function` cannot have a record as input or output."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -685,6 +685,20 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
stub_functions_must_not_be_inlines {
|
||||
args: (),
|
||||
msg: format!("Function stubs must be transitions or functions not inlines"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
stub_functions_must_be_empty {
|
||||
args: (),
|
||||
msg: format!("Functions stubs must be empty"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
array_empty {
|
||||
args: (),
|
||||
@ -712,4 +726,25 @@ create_messages!(
|
||||
msg: format!("An array cannot have a record as an element type"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
stubs_cannot_have_non_record_structs {
|
||||
args: (),
|
||||
msg: format!("Stubs can only have records, transitions, functions, mappings and imports -- found non-record struct"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
stubs_cannot_have_const_declarations {
|
||||
args: (),
|
||||
msg: format!("Stubs can only have records, transitions, functions, mappings and imports -- found const declaration"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
stub_name_mismatch {
|
||||
args: (stub_name: impl Display, program_name: impl Display),
|
||||
msg: format!("`stub` name `{stub_name}` does not match program name `{program_name}`"),
|
||||
help: Some("Check that the name you used as a dependency in program.json matches the name you used to import the program in the main leo file.".to_string()),
|
||||
}
|
||||
);
|
||||
|
@ -15,5 +15,5 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/// This module contains the Input error definitions.
|
||||
pub mod input_errors;
|
||||
pub use self::input_errors::*;
|
||||
pub mod util_errors;
|
||||
pub use self::util_errors::*;
|
147
errors/src/errors/utils/util_errors.rs
Normal file
147
errors/src/errors/utils/util_errors.rs
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::create_messages;
|
||||
use std::{
|
||||
error::Error as ErrorArg,
|
||||
fmt::{Debug, Display},
|
||||
};
|
||||
|
||||
create_messages!(
|
||||
/// InputError enum that represents all the errors for the `utils` crate.
|
||||
UtilError,
|
||||
code_mask: 10000i32,
|
||||
code_prefix: "UTL",
|
||||
|
||||
@formatted
|
||||
util_file_io_error {
|
||||
args: (msg: impl Display, err: impl ErrorArg),
|
||||
msg: format!("File system io error: {msg}. Error: {err}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
toml_serizalization_error {
|
||||
args: (error: impl ErrorArg),
|
||||
msg: format!("TOML serialization error: {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
json_serialization_error {
|
||||
args: (error: impl ErrorArg),
|
||||
msg: format!("JSON serialization error: {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
snarkvm_parsing_error {
|
||||
args: (),
|
||||
msg: format!("SnarkVM failure to parse `.aleo` program"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
circular_dependency_error {
|
||||
args: (),
|
||||
msg: format!("Circular dependency detected"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
network_error {
|
||||
args: (url: impl Display, status: impl Display),
|
||||
msg: format!("Failed network request to {url}. Status: {status}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
duplicate_dependency_name_error {
|
||||
args: (dependency: impl Display),
|
||||
msg: format!("Duplicate dependency found: {dependency}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
reqwest_error {
|
||||
args: (error: impl Display),
|
||||
msg: format!("{}", error),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_open_file {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to open file {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_read_file {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to read file {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_deserialize_file {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to deserialize file {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
failed_to_retrieve_dependencies {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to retrieve dependencies. {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
missing_network_error {
|
||||
args: (dependency: impl Display),
|
||||
msg: format!("Dependency {dependency} is missing a network specification"),
|
||||
help: Some("Add a network specification to the dependency in the `program.json` file. Example: `network: \"testnet3\"`".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
missing_path_error {
|
||||
args: (dependency: impl Display),
|
||||
msg: format!("Local dependency {dependency} is missing a path specification"),
|
||||
help: Some("Add a path in the `program.json` file to the dependency project root . Example: `path: \"../../board\"`".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
program_name_mismatch_error {
|
||||
args: (program_json_name: impl Display, dep_name: impl Display, path: impl Display),
|
||||
msg: format!("Name mismatch: Local program at path `{path}` is named `{program_json_name}` in `program.json` but `{dep_name}` in the program that imports it"),
|
||||
help: Some("Change one of the names to match the other".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
snarkvm_error_building_program_id {
|
||||
args: (),
|
||||
msg: format!("Snarkvm error building program id"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
failed_to_retrieve_from_endpoint {
|
||||
args: (endpoint: impl Display, error: impl ErrorArg),
|
||||
msg: format!("Failed to retrieve from endpoint `{endpoint}`. Error: {error}"),
|
||||
help: None,
|
||||
}
|
||||
);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user