mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-26 11:45:00 +03:00
commit
72b2095b67
101
README.md
101
README.md
@ -1,6 +1,6 @@
|
|||||||
# The Leo Programming Language
|
# The Leo Programming Language
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.com/AleoHQ/leo.svg?token=Xy7ht9JdPvr4xSgbPruF&branch=master)](https://travis-ci.com/AleoHQ/leo)
|
![CI](https://github.com/AleoHQ/leo/workflows/CI/badge.svg)
|
||||||
[![codecov](https://codecov.io/gh/AleoHQ/leo/branch/master/graph/badge.svg?token=S6MWO60SYL)](https://codecov.io/gh/AleoHQ/leo)
|
[![codecov](https://codecov.io/gh/AleoHQ/leo/branch/master/graph/badge.svg?token=S6MWO60SYL)](https://codecov.io/gh/AleoHQ/leo)
|
||||||
|
|
||||||
## Compiler Architecture
|
## Compiler Architecture
|
||||||
@ -43,8 +43,8 @@ Leo supports `let` and `const` keywords for variable definition.
|
|||||||
|
|
||||||
**Constant** variables do not define a variable in the constraint system. Their value is constrained in the circuit on computation with an **allocated** variable.
|
**Constant** variables do not define a variable in the constraint system. Their value is constrained in the circuit on computation with an **allocated** variable.
|
||||||
**Constant** variables cannot be mutable. They have the same functionality as `const` variables in other languages.
|
**Constant** variables cannot be mutable. They have the same functionality as `const` variables in other languages.
|
||||||
```rust
|
```js
|
||||||
function addOne() -> {
|
function add_one() -> {
|
||||||
let a = 0u8; // allocated, value enforced on this line
|
let a = 0u8; // allocated, value enforced on this line
|
||||||
const b = 1u8; // constant, value not enforced yet
|
const b = 1u8; // constant, value not enforced yet
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ Computations are expressed in terms of arithmetic circuits, in particular rank-1
|
|||||||
* All defined variables in Leo are immutable by default.
|
* All defined variables in Leo are immutable by default.
|
||||||
* Variables can be made mutable with the `mut` keyword.
|
* Variables can be made mutable with the `mut` keyword.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
function main() {
|
function main() {
|
||||||
let a = 0u32;
|
let a = 0u32;
|
||||||
//a = 1 <- Will fail
|
//a = 1 <- Will fail
|
||||||
@ -67,10 +67,23 @@ function main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Addresses
|
||||||
|
|
||||||
|
Addresses are defined to enable compiler-optimized routines for parsing and operating over addresses. These semantics will be accompanied by a standard library in a future sprint.
|
||||||
|
|
||||||
|
```js
|
||||||
|
function main(owner: address) {
|
||||||
|
let sender = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
|
||||||
|
let receiver: address = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
|
||||||
|
assert_eq!(owner, sender);
|
||||||
|
assert_eq!(sender, receiver);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Booleans
|
## Booleans
|
||||||
|
|
||||||
Explicit types are optional.
|
Explicit types are optional.
|
||||||
```rust
|
```js
|
||||||
function main() -> bool {
|
function main() -> bool {
|
||||||
let a: bool = true || false;
|
let a: bool = true || false;
|
||||||
let b = false && false;
|
let b = false && false;
|
||||||
@ -87,7 +100,7 @@ function main() -> bool {
|
|||||||
|
|
||||||
### Integers
|
### Integers
|
||||||
Supported integer types: `u8`, `u16`, `u32`, `u64`, `u128`
|
Supported integer types: `u8`, `u16`, `u32`, `u64`, `u128`
|
||||||
```rust
|
```js
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
let a = 2u32; // explicit type
|
let a = 2u32; // explicit type
|
||||||
let a: u32 = 1 + 1; // explicit type
|
let a: u32 = 1 + 1; // explicit type
|
||||||
@ -101,7 +114,7 @@ function main() -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Field Elements
|
### Field Elements
|
||||||
```rust
|
```js
|
||||||
function main() -> field {
|
function main() -> field {
|
||||||
let a = 1000field; // explicit type
|
let a = 1000field; // explicit type
|
||||||
let a: field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // explicit type
|
let a: field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // explicit type
|
||||||
@ -113,11 +126,11 @@ function main() -> field {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Affine Points
|
### Group Elements
|
||||||
The set of affine points on the elliptic curve passed into the leo compiler forms a group.
|
An affine point on the elliptic curve passed into the Leo compiler forms a group.
|
||||||
Leo supports this set as a primitive data type.
|
Leo supports this set as a primitive data type.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
function main() -> group {
|
function main() -> group {
|
||||||
let a = 1000group; // explicit type
|
let a = 1000group; // explicit type
|
||||||
let a = (21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617)group; // explicit type
|
let a = (21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617)group; // explicit type
|
||||||
@ -128,7 +141,7 @@ function main() -> group {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Operator Assignment Statements
|
### Operator Assignment Statements
|
||||||
```rust
|
```js
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
let mut a = 10;
|
let mut a = 10;
|
||||||
a += 5;
|
a += 5;
|
||||||
@ -143,7 +156,7 @@ function main() -> u32 {
|
|||||||
|
|
||||||
## Arrays
|
## Arrays
|
||||||
Leo supports static arrays with fixed length.
|
Leo supports static arrays with fixed length.
|
||||||
```rust
|
```js
|
||||||
function main() -> u32[2] {
|
function main() -> u32[2] {
|
||||||
// initialize an integer array with integer values
|
// initialize an integer array with integer values
|
||||||
let mut a: u32[3] = [1, 2, 3];
|
let mut a: u32[3] = [1, 2, 3];
|
||||||
@ -171,7 +184,7 @@ function main() -> u32[2] {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Multidimensional Arrays
|
### Multidimensional Arrays
|
||||||
```rust
|
```js
|
||||||
function main() -> u32[3][2] {
|
function main() -> u32[3][2] {
|
||||||
let m = [[0u32, 0u32], [0u32, 0u32]];
|
let m = [[0u32, 0u32], [0u32, 0u32]];
|
||||||
|
|
||||||
@ -191,7 +204,7 @@ Ternary `if [cond] ? [first] : [second];` expressions are the cheapest form of c
|
|||||||
Since `first` and `second` are expressions, we can resolve their values before proceeding execution.
|
Since `first` and `second` are expressions, we can resolve their values before proceeding execution.
|
||||||
In the underlying circuit, this is a single bit multiplexer.
|
In the underlying circuit, this is a single bit multiplexer.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
let y = if 3==3 ? 1 : 5;
|
let y = if 3==3 ? 1 : 5;
|
||||||
return y
|
return y
|
||||||
@ -202,7 +215,7 @@ function main() -> u32 {
|
|||||||
Leo supports the traditional `if [cond] { [first] } else { [second] }` which can be chained using `else if`.
|
Leo supports the traditional `if [cond] { [first] } else { [second] }` which can be chained using `else if`.
|
||||||
Since `first` and `second` are one or more statements, they resolve to separate circuits which will all be evaluated.
|
Since `first` and `second` are one or more statements, they resolve to separate circuits which will all be evaluated.
|
||||||
In the underlying circuit this can be thought of as a demultiplexer.
|
In the underlying circuit this can be thought of as a demultiplexer.
|
||||||
```rust
|
```js
|
||||||
function main(a: bool, b: bool) -> u32 {
|
function main(a: bool, b: bool) -> u32 {
|
||||||
let mut res = 0u32;
|
let mut res = 0u32;
|
||||||
if a {
|
if a {
|
||||||
@ -217,7 +230,7 @@ function main(a: bool, b: bool) -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### For loop
|
### For loop
|
||||||
```rust
|
```js
|
||||||
function main() -> fe {
|
function main() -> fe {
|
||||||
let mut a = 1field;
|
let mut a = 1field;
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
@ -228,7 +241,7 @@ function main() -> fe {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
```rust
|
```js
|
||||||
function test1(a : u32) -> u32 {
|
function test1(a : u32) -> u32 {
|
||||||
return a + 1
|
return a + 1
|
||||||
}
|
}
|
||||||
@ -248,7 +261,7 @@ function main() -> u32 {
|
|||||||
|
|
||||||
|
|
||||||
### Function Scope
|
### Function Scope
|
||||||
```rust
|
```js
|
||||||
function foo() -> field {
|
function foo() -> field {
|
||||||
// return myGlobal <- not allowed
|
// return myGlobal <- not allowed
|
||||||
return 42field
|
return 42field
|
||||||
@ -262,7 +275,7 @@ function main() -> field {
|
|||||||
|
|
||||||
### Multiple returns
|
### Multiple returns
|
||||||
Functions can return tuples whose types are specified in the function signature.
|
Functions can return tuples whose types are specified in the function signature.
|
||||||
```rust
|
```js
|
||||||
function test() -> (u32, u32[2]) {
|
function test() -> (u32, u32[2]) {
|
||||||
return 1, [2, 3]
|
return 1, [2, 3]
|
||||||
}
|
}
|
||||||
@ -277,13 +290,13 @@ function main() -> u32[3] {
|
|||||||
### Function inputs
|
### Function inputs
|
||||||
Main function inputs are allocated private variables in the program's constraint system.
|
Main function inputs are allocated private variables in the program's constraint system.
|
||||||
`a` is implicitly private.
|
`a` is implicitly private.
|
||||||
```rust
|
```js
|
||||||
function main(a: field) -> field {
|
function main(a: field) -> field {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Normal function inputs are passed by value.
|
Normal function inputs are passed by value.
|
||||||
```rust
|
```js
|
||||||
function test(mut a: u32) {
|
function test(mut a: u32) {
|
||||||
a = 0;
|
a = 0;
|
||||||
}
|
}
|
||||||
@ -301,7 +314,7 @@ Circuits in Leo are similar to classes in object oriented langauges. Circuits ar
|
|||||||
|
|
||||||
|
|
||||||
Members can be defined as fields which hold primitive values
|
Members can be defined as fields which hold primitive values
|
||||||
```rust
|
```js
|
||||||
circuit Point {
|
circuit Point {
|
||||||
x: u32
|
x: u32
|
||||||
y: u32
|
y: u32
|
||||||
@ -313,34 +326,34 @@ function main() -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Members can also be defined as functions.
|
Members can also be defined as functions.
|
||||||
```rust
|
```js
|
||||||
circuit Circ {
|
circuit Foo {
|
||||||
function echo(x: u32) -> u32 {
|
function echo(x: u32) -> u32 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
let c = Circ { };
|
let c = Foo { };
|
||||||
return c.echo(1u32)
|
return c.echo(1u32)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Circuit functions can be made static, enabling them to be called without instantiation.
|
Circuit functions can be made static, enabling them to be called without instantiation.
|
||||||
```rust
|
```js
|
||||||
circuit Circ {
|
circuit Foo {
|
||||||
static function echo(x: u32) -> u32 {
|
static function echo(x: u32) -> u32 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
return Circ::echo(1u32)
|
return Foo::echo(1u32)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Self` keyword is supported in circuit functions.
|
The `Self` keyword is supported in circuit functions.
|
||||||
```rust
|
```js
|
||||||
circuit Circ {
|
circuit Circ {
|
||||||
b: bool
|
b: bool
|
||||||
|
|
||||||
@ -358,19 +371,19 @@ function main() -> Circ {
|
|||||||
## Imports
|
## Imports
|
||||||
Leo supports importing functions and circuits by name into the current file with the following syntax:
|
Leo supports importing functions and circuits by name into the current file with the following syntax:
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
import [package].[name];
|
import [package].[name];
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Import Aliases
|
#### Import Aliases
|
||||||
To import a name using an alias:
|
To import a name using an alias:
|
||||||
```rust
|
```js
|
||||||
import [package].[name] as [alias];
|
import [package].[name] as [alias];
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Import Multiple
|
#### Import Multiple
|
||||||
To import multiple names from the same package:
|
To import multiple names from the same package:
|
||||||
```rust
|
```js
|
||||||
import [package].(
|
import [package].(
|
||||||
[name_1],
|
[name_1],
|
||||||
[name_2] as [alias],
|
[name_2] as [alias],
|
||||||
@ -380,20 +393,20 @@ import [package].(
|
|||||||
#### Import Star
|
#### Import Star
|
||||||
To import all symbols from a package:
|
To import all symbols from a package:
|
||||||
Note that this will only import symbols from the package library `lib.leo` file.
|
Note that this will only import symbols from the package library `lib.leo` file.
|
||||||
```rust
|
```js
|
||||||
import [package].*;
|
import [package].*;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Local
|
### Local
|
||||||
You can import from a local file in the `src/` directory by using its `[file].leo` as the `[package]` name.
|
You can import from a local file in the `src/` directory by using its `[file].leo` as the `[package]` name.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
import [file].[name];
|
import [file].[name];
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
`src/bar.leo`
|
`src/bar.leo`
|
||||||
```rust
|
```js
|
||||||
circuit Bar {
|
circuit Bar {
|
||||||
b: u32
|
b: u32
|
||||||
}
|
}
|
||||||
@ -404,7 +417,7 @@ function baz() -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
`src/main.leo`
|
`src/main.leo`
|
||||||
```rust
|
```js
|
||||||
import bar.(
|
import bar.(
|
||||||
Bar,
|
Bar,
|
||||||
baz
|
baz
|
||||||
@ -418,20 +431,20 @@ function main() {
|
|||||||
|
|
||||||
### Foreign
|
### Foreign
|
||||||
You can import from a foreign package in the `imports/` directory using its `[package]` name.
|
You can import from a foreign package in the `imports/` directory using its `[package]` name.
|
||||||
```rust
|
```js
|
||||||
import [package].[name];
|
import [package].[name];
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
`imports/bar/src/lib.leo`
|
`imports/bar/src/lib.leo`
|
||||||
```rust
|
```js
|
||||||
circuit Bar {
|
circuit Bar {
|
||||||
b: u32
|
b: u32
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`src/main.leo`
|
`src/main.leo`
|
||||||
```rust
|
```js
|
||||||
import bar.Bar;
|
import bar.Bar;
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@ -441,7 +454,7 @@ function main() {
|
|||||||
|
|
||||||
### Package Paths
|
### Package Paths
|
||||||
Leo treats directories as package names when importing.
|
Leo treats directories as package names when importing.
|
||||||
```rust
|
```js
|
||||||
import [package].[directory].[file].[name]
|
import [package].[directory].[file].[name]
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -450,14 +463,14 @@ We wish to import the `Baz` circuit from the `baz.leo` file in the `bar` directo
|
|||||||
|
|
||||||
|
|
||||||
`imports/foo/src/bar/baz.leo`
|
`imports/foo/src/bar/baz.leo`
|
||||||
```rust
|
```js
|
||||||
circuit Baz {
|
circuit Baz {
|
||||||
b: u32
|
b: u32
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`src/main.leo`
|
`src/main.leo`
|
||||||
```rust
|
```js
|
||||||
import foo.bar.baz.Baz;
|
import foo.bar.baz.Baz;
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@ -470,7 +483,7 @@ function main() {
|
|||||||
### Assert Equals
|
### Assert Equals
|
||||||
This will enforce that the two values are equal in the constraint system.
|
This will enforce that the two values are equal in the constraint system.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
function main() {
|
function main() {
|
||||||
assert_eq!(45, 45);
|
assert_eq!(45, 45);
|
||||||
|
|
||||||
@ -484,7 +497,7 @@ function main() {
|
|||||||
|
|
||||||
Use the `test` keyword to add tests to a leo program. Tests must have 0 function inputs and 0 function returns.
|
Use the `test` keyword to add tests to a leo program. Tests must have 0 function inputs and 0 function returns.
|
||||||
|
|
||||||
```rust
|
```js
|
||||||
function main(a: u32) -> u32 {
|
function main(a: u32) -> u32 {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user