Merge branch 'master' into compiler-tests

This commit is contained in:
damirka 2021-05-12 20:02:03 +03:00
commit cb2bd62ea9
78 changed files with 768 additions and 524 deletions

28
Cargo.lock generated
View File

@ -424,10 +424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]] [[package]]
name = "cpuid-bool" name = "cpufeatures"
version = "0.1.2" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" checksum = "5cd5a7748210e7ec1a9696610b1015e6e31fbf58f77a160801f124bd1c36592a"
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
@ -2488,9 +2488,9 @@ dependencies = [
[[package]] [[package]]
name = "self_update" name = "self_update"
version = "0.26.0" version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9031099ba3962ce8faaff991066bcbe6ec1f7ccb0be12a4b56733028ae090054" checksum = "6fb85f1802f7b987237b8525c0fde86ea86f31c957c1875467c727d5b921179c"
dependencies = [ dependencies = [
"hyper", "hyper",
"indicatif", "indicatif",
@ -2616,13 +2616,13 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.3" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" checksum = "d8f6b75b17576b792bef0db1bcc4b8b8bcdf9506744cf34b974195487af6cff2"
dependencies = [ dependencies = [
"block-buffer 0.9.0", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpuid-bool", "cpufeatures",
"digest 0.9.0", "digest 0.9.0",
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
@ -3136,9 +3136,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.25" version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"pin-project-lite", "pin-project-lite",
@ -3159,9 +3159,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.17" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@ -3199,9 +3199,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.2.17" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa" checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"chrono", "chrono",

View File

@ -125,7 +125,7 @@ version = "0.11.3"
features = [ "blocking", "json", "multipart" ] features = [ "blocking", "json", "multipart" ]
[dependencies.self_update] [dependencies.self_update]
version = "0.26.0" version = "0.27.0"
features = [ "archive-zip" ] features = [ "archive-zip" ]
[dependencies.serde] [dependencies.serde]

View File

@ -105,7 +105,7 @@ fn resolve_import_package_access(
package: &PackageAccess, package: &PackageAccess,
) { ) {
match package { match package {
PackageAccess::Star(span) => { PackageAccess::Star { span } => {
output.push((package_segments, ImportSymbol::All, span.clone())); output.push((package_segments, ImportSymbol::All, span.clone()));
} }
PackageAccess::SubPackage(subpackage) => { PackageAccess::SubPackage(subpackage) => {
@ -414,7 +414,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
.map(|(module, _)| leo_ast::ImportStatement { .map(|(module, _)| leo_ast::ImportStatement {
package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package { package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package {
name: Identifier::new(module.clone().into()), name: Identifier::new(module.clone().into()),
access: leo_ast::PackageAccess::Star(Span::default()), access: leo_ast::PackageAccess::Star { span: Span::default() },
span: Default::default(), span: Default::default(),
}), }),
span: Span::default(), span: Span::default(),

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}
} }

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(self, new: u8) { function set_a(self, new: u8) {
self.a = new; self.a = new;

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
f: u32, f: u32;
function bar() -> u32 { function bar() -> u32 {
return f; return f;

View File

@ -1,6 +1,6 @@
// Circuits are immutable by default. // Circuits are immutable by default.
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u32, a: u32;
} }
circuit Bar { circuit Bar {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32, x: u32;
function add_x(self, y: u32) -> u32 { function add_x(self, y: u32) -> u32 {
return self.x + y; return self.x + y;

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32, x: u32;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
foo: u32, foo: u32;
function bar() -> u32 { function bar() -> u32 {
return 1u32; return 1u32;

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(mut self, new: u8) { function set_a(mut self, new: u8) {
self.a = new; self.a = new;

View File

@ -5,7 +5,7 @@ function main() {
} }
circuit Foo { circuit Foo {
a: u32 a: u32;
function bar(mut self) { function bar(mut self) {
if true { if true {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
a: u8, a: u8;
} }
function main() { function main() {

View File

@ -1,5 +1,5 @@
circuit PedersenHash { circuit PedersenHash {
parameters: [u32; 512] parameters: [u32; 512];
function new(const parameters: [u32; 512]) -> Self { function new(const parameters: [u32; 512]) -> Self {
return Self { parameters: parameters }; return Self { parameters: parameters };

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
f: u32, f: u32;
function bar(self) -> u32 { function bar(self) -> u32 {
return self.f; return self.f;

View File

@ -58,8 +58,8 @@ fn test_imports() {
let mut imports = crate::mocked_resolver(&context); let mut imports = crate::mocked_resolver(&context);
let test_import = r#" let test_import = r#"
circuit Point { circuit Point {
x: u32 x: u32;
y: u32 y: u32;
} }
function foo() -> u32 { function foo() -> u32 {

View File

@ -1,3 +1,3 @@
circuit Bat { circuit Bat {
t: u32 t: u32;
} }

View File

@ -1,7 +1,7 @@
circuit Baz { circuit Baz {
z: u32 z: u32;
} }
circuit Bazzar { circuit Bazzar {
a: u32 a: u32;
} }

View File

@ -1,3 +1,3 @@
circuit Bar { circuit Bar {
r: u32 r: u32;
} }

View File

@ -1,3 +1,3 @@
circuit Car { circuit Car {
c: u32 c: u32;
} }

View File

@ -1,6 +1,6 @@
circuit Point { circuit Point {
x: u32 x: u32;
y: u32 y: u32;
} }
function foo() -> u32 { function foo() -> u32 {

View File

@ -1,6 +1,6 @@
// Adding the `mut` keyword makes a circuit variable mutable. // Adding the `mut` keyword makes a circuit variable mutable.
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -1,6 +1,6 @@
// Adding the `mut` keyword makes a circuit variable mutable. // Adding the `mut` keyword makes a circuit variable mutable.
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -36,7 +36,7 @@ impl CanonicalizeError {
} }
pub fn invalid_array_dimension_size(span: &Span) -> Self { pub fn invalid_array_dimension_size(span: &Span) -> Self {
let message = "recieved dimension size of 0, expected it to be 1 or larger.".to_string(); let message = "received dimension size of 0, expected it to be 1 or larger.".to_string();
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }

View File

@ -21,7 +21,7 @@ use std::fmt;
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum PackageAccess { pub enum PackageAccess {
Star(Span), Star { span: Span },
SubPackage(Box<Package>), SubPackage(Box<Package>),
Symbol(ImportSymbol), Symbol(ImportSymbol),
Multiple(Packages), Multiple(Packages),
@ -30,7 +30,7 @@ pub enum PackageAccess {
impl Node for PackageAccess { impl Node for PackageAccess {
fn span(&self) -> &Span { fn span(&self) -> &Span {
match self { match self {
PackageAccess::Star(span) => span, PackageAccess::Star { span } => span,
PackageAccess::SubPackage(package) => &package.span, PackageAccess::SubPackage(package) => &package.span,
PackageAccess::Symbol(package) => &package.span, PackageAccess::Symbol(package) => &package.span,
PackageAccess::Multiple(package) => &package.span, PackageAccess::Multiple(package) => &package.span,
@ -39,7 +39,7 @@ impl Node for PackageAccess {
fn set_span(&mut self, span: Span) { fn set_span(&mut self, span: Span) {
match self { match self {
PackageAccess::Star(package) => *package = span, PackageAccess::Star { span } => *span = span.clone(),
PackageAccess::SubPackage(package) => package.span = span, PackageAccess::SubPackage(package) => package.span = span,
PackageAccess::Symbol(package) => package.span = span, PackageAccess::Symbol(package) => package.span = span,
PackageAccess::Multiple(package) => package.span = span, PackageAccess::Multiple(package) => package.span = span,
@ -50,7 +50,7 @@ impl Node for PackageAccess {
impl PackageAccess { impl PackageAccess {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
PackageAccess::Star(ref _span) => write!(f, "*"), PackageAccess::Star { .. } => write!(f, "*"),
PackageAccess::SubPackage(ref package) => write!(f, "{}", package), PackageAccess::SubPackage(ref package) => write!(f, "{}", package),
PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol), PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol),
PackageAccess::Multiple(ref packages) => { PackageAccess::Multiple(ref packages) => {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32 x: u32;
function new() -> Self { function new() -> Self {
let new: Self = Self { let new: Self = Self {

View File

@ -1,5 +1,5 @@
circuit Foo { circuit Foo {
x: u32 x: u32;
function new() -> Self { function new() -> Self {
let new: Self = Self { let new: Self = Self {

View File

@ -1,6 +1,6 @@
circuit Foo { circuit Foo {
f: u8, f: u8;
y: (u8, u8), y: (u8, u8);
function z (mut self) -> u16 { function z (mut self) -> u16 {
self.y.0 += 1u8; self.y.0 += 1u8;

View File

@ -21,20 +21,19 @@ DRAFT
The purpose of this proposal is to provide initial support for strings in Leo. The purpose of this proposal is to provide initial support for strings in Leo.
Since strings are sequences of characters, Since strings are sequences of characters,
the proposal inextricably also involves characters. the proposal inextricably also involves characters.
This proposal is described as 'initial,' This proposal is described as initial,
because it provides some basic features that we may extend in the future; because it provides some basic features that we may extend in the future;
the initial features should be sufficiently simple and conservative the initial features should be sufficiently simple and conservative
that they should not limit the design of the future features. that they should not limit the design of the future features.
This proposal adds a new scalar type for characters This proposal adds a new scalar type for characters,
along with a new kind of literals to denote characters. along with a new kind of literals to denote characters.
A string is then simply as an array of characters, A string is then simply an array of characters,
but this proposal also adds a new kind of literals to denote strings but this proposal also adds a new kind of literals to denote strings
more directly than via character array construction expressions. more directly than via character array construction expressions.
Along with equality and inequality, which always apply to every Leo type, Along with equality and inequality, which always apply to every Leo type,
this proposal also introduces operations for this proposal also introduces some operations on characters and strings
_[TODO: Summarize initial set of built-in or library operations that can be implemented over time.
on characters and strings.]_.
By not prescribing a new type for strings, By not prescribing a new type for strings,
this initial proposal leaves the door open this initial proposal leaves the door open
@ -48,25 +47,23 @@ simple ones like URLs and token ticker symbols,
and more complex ones like Bech32 encoding, and more complex ones like Bech32 encoding,
edit distance in strings representing proteins, edit distance in strings representing proteins,
and zero-knowledge proofs of occurrences or absences of patterns in textual logs. and zero-knowledge proofs of occurrences or absences of patterns in textual logs.
_[TODO: Add more use cases if needed.]_
# Design # Design
Since strings are sequences of characters, Since strings are sequences of characters,
a design for strings inextricably also involves a design for characters. a design for strings inextricably also involves a design for characters.
Thus, we first present a design for characters, then for strings. Thus, we first present a design for both characters and strings.
After that, we discuss the relation with Leo's existing format strings.
We conclude this design section
with a discussion of possible future extensions.
## Characters ## Characters
We add a new scalar type, `char` for characters. We add a new scalar type, `char` for characters.
In accord with Leo's strong typing, In accord with Leo's strong typing,
this new type is separate from all the other scalar types. this new type is separate from all the other scalar types.
Type casts (a future feature of Leo) will be needed
to convert between `char` and other types.
The set of values of type `char` is isomorphic to The set of values of type `char` is isomorphic to
the set of Unicode code points from 0 to 10FFFFh (both inclusive). the set of Unicode code points from 0 to 10FFFF (both inclusive).
That is, we support Unicode characters, more precisely code points That is, we support Unicode characters, more precisely code points
(this may include some invalid code points, (this may include some invalid code points,
but it is simpler to allow every code point in that range). but it is simpler to allow every code point in that range).
@ -81,38 +78,73 @@ e.g. `'a'`, `'*'`, and `'"'`.
Single quotes must be escaped with a backslash, i.e. `'\''`; Single quotes must be escaped with a backslash, i.e. `'\''`;
backslashes must be escaped as well, i.e. `'\\'` backslashes must be escaped as well, i.e. `'\\'`
We allow other backslash escapes We allow other backslash escapes
for commonly used characters that are not otherwise easily denoted, for commonly used characters that are not otherwise easily denoted.
namely _[TODO: Decide which other escapes we want to allow, e.g. `'\n'`.]_ This is the complete list of single-character backslash escapes:
* `\n` * `\'` for code point 39 (single quote)
* `\r` * `\"` for code point 34 (double quote)
* `\t` * `\\` for code point 92 (backslash)
* `\0` * `\n` for code point 10 (line feed)
* `\'` * `\r` for code point 13 (carriage return)
* `\"` * `\t` for core point 9 (horizontal tab)
* `\0` for code point 0 (the null character)
We also allow ASCII escapes of the form `\xOH`,
where `O` is an octal digit and `H` is a hexadecimal digit
(both uppercase and lowercase are allowed).
These represent ASCII code points, i.e. from 0 to 127 (both inclusive).
We also allow Unicode escapes of the form `'\u{X}'`, We also allow Unicode escapes of the form `'\u{X}'`,
where `X` is a sequence of one to six hex digits where `X` is a sequence of one to six hex digits
(both uppercase and lowercase letters are allowed) (both uppercase and lowercase letters are allowed)
whose value must be between 0 and 10FFFF, inclusive. whose value must be between 0 and 10FFFF, inclusive.
Note that the literal character is assembled by the compiler---for Note that the literal character is assembled by the compiler---for
creating literals, there is no need for the circuit to know creating literals, there is no need for the circuit to know
which codepoints are disallowed. which code points are disallowed.
_[TODO: Do we want a different notation for Unicode escapes?
Note that the `{` `}` delimiters are motivated by the fact that
there may be a varying number of hex digits in this notation.]_
This notation is supported by both Javascript and Rust.
_[TODO: Which (initial) built-in or library operations The equality operators `==` and `!=` are automatically available for `char`.
do we want to provide for `char` values?]_ Given that characters are essentially code points,
- [ ] is_alphabetic - Returns `true` if the `char` has the `Alphabetic` property. we may also support the ordering operators `<`, `<=`, `>`, and `>=`;
- [ ] is_ascii - Returns `true` if the `char` is in the `ASCII` range. these may be useful to check whether a character is in certain range.
- [ ] is_ascii_alphabetic - Returns `true` if the `char` is in the `ASCII Alphabetic` range.
- [ ] is_lowercase - Returns `true` if the `char` has the `Lowercase` property.
- [ ] is_numeric - Returns `true` if the `char` has one of the general categories for numbers.
- [ ] is_uppercase - Returns `true` if the `char` has the `Uppercase` property.
- [ ] is_whitespace - Returns `true` if the `char` has the `White_Space` property.
- [ ] to_digit - Converts the `char` to the given `radix` format.
Below is a list of possible operations we could support on characters.
It should be fairly easy to add more.
- [ ] `is_alphabetic` - Returns `true` if the `char` has the `Alphabetic` property.
- [ ] `is_ascii` - Returns `true` if the `char` is in the `ASCII` range.
- [ ] `is_ascii_alphabetic` - Returns `true` if the `char` is in the `ASCII Alphabetic` range.
- [ ] `is_lowercase` - Returns `true` if the `char` has the `Lowercase` property.
- [ ] `is_numeric` - Returns `true` if the `char` has one of the general categories for numbers.
- [ ] `is_uppercase` - Returns `true` if the `char` has the `Uppercase` property.
- [ ] `is_whitespace` - Returns `true` if the `char` has the `White_Space` property.
- [ ] `to_digit` - Converts the `char` to the given `radix` format.
- [ ] `from_digit` - Inverse of to_digit.
- [ ] `to_uppercase` - Converts lowercase to uppercase, leaving others unchanged.
- [ ] `to_lowercase` - Converts uppercase to lowercase, leaving others unchanged.
It seems natural to convert between `char` values
and `u8` or `u16` or `u32` values, under suitable range conditions;
perhaps also between `char` values and
(non-negative) `i8` or `i16` or `i32` values.
This will be accomplished as part of the type casting extension of Leo.
The following code sample illustrates three ways of defining characters:
character literal, single-character escapes, and Unicode escapes.
```js
function main() -> [char; 5] {
// using char literals to form an array
const world: [char; 5] = ['w', 'o', 'r', 'l', 'd'];
// escaped characters
const escaped: [char; 4] = ['\n', '\t', '\\', '\''];
// unicode escapes - using emoji character 😊
const smiling_face: char = '\u{1F60A}';
return [smiling_face, ...escaped];
}
```
## Strings ## Strings
@ -133,12 +165,6 @@ Double quotes must be escaped with a backslash, e.g. `"say \"hi\""`;
backslashes must be escaped as well, e.g. `"c:\\dir"`. backslashes must be escaped as well, e.g. `"c:\\dir"`.
We allow the same backslash escapes allowed for character literals We allow the same backslash escapes allowed for character literals
(see the section on characters above). (see the section on characters above).
_[TODO: There is a difference in the treatment of single and double quotes:
the former are allowed in string literals but not character literals,
while the latter are allowed in character literals but not string literals;
this asymmetry is also present in Java.
However, for simplicity, we may want to symmetrically disallow
both single and double quotes in both character and string literals.]_
We also allow the same Unicode escapes allowed in character literals We also allow the same Unicode escapes allowed in character literals
(described in the section on characters above). (described in the section on characters above).
In any case, the type of a string literal is `[char; N]`, In any case, the type of a string literal is `[char; N]`,
@ -160,30 +186,55 @@ in a future design iteration,
a richer type for strings, a richer type for strings,
as discussed in the section about future extensions below. as discussed in the section about future extensions below.
_[TODO: Which (initial) built-in or library operations Recall that empty arrays are disallowed in Leo.
do we want to provide for `[char; N]` values that are not already (The reason is that arrays,
available with the existing array operations?]_ which must have a size known at compile time and are not resizable,
- [ ] `u8` to `[char; 2]` hexstring, .., `u128` to `[char; 32]` hexstring are flattened into their elements when compiling to R1CS;
- [ ] field element to `[char; 64]` hexstring. (Application can test leading zeros and slice them out if it needs to return, say, a 40-hex-digit string) thus, an empty array would be flattened into nothing.)
- [ ] len - Returns the length of the `string`. Therefore, in this initial design empty strings must be disallowed as well.
- [ ] is_empty - Returns `true` if the `string` is empty. A future type of resizable strings will support empty strings.
- [ ] pop - Pops a `char` to the `string`.
- [ ] push - Pushes a `char` to the `string`.
- [ ] append - Appends a `string` to the `string`.
- [ ] clear - Empties the `string`.
- [ ] _[TODO: more?]_
## Input and Output of Literal Characters and Strings Because array, and therefore string, sizes must be known at compile time,
there is no point to having an operation to return the length of a string.
This operation will be supported for a future type of resizable strings.
Since UTF-8 is a standard encoding, it would make sense for Below are some examples of array operations
the literal characters and strings in the `.in` file that are also common for strings in other programming languages:
to be automatically converted to UTF-32 by the Leo compiler. * `[...s1, ...s2]` concatenates the strings `s1` and `s2`.
However, the size of a string can be confusing since multiple * `[c, ...s]` adds the character `c` in front of the string `s`.
Unicode code points can be composed into a single glyph which * `s[i]` extracts the `i`-th character from the string `s`.
then appears to be a single character. If a parameter of type `[char; 10]` * `s[1..]` removes the first character from the string `s`.
[if that is the syntax we decide on] is passed a literal string
of a different size, the error message should explain that the Below is a list of possible operations we could support on strings.
size must be the number of codepoints needed to encode the string. It should be fairly easy to add more.
- [ ] `u8` to `[char; 2]` hexstring, .., `u128` to `[char; 32]` hexstring.
- [ ] Field element to `[char; 64]` hexstring. (Application can test leading zeros and slice them out if it needs to return, say, a 40-hex-digit string.)
- [ ] Apply `to_uppercase` (see above) to every character.
- [ ] Apply `to_lowercase` (see above) to every character.
Note that the latter two could be also realize via simple loops through the string.
Given the natural conversions between `char` values and integer values discussed earlier,
it may be natural to also support element-wise conversions between strings and arrays of integers.
This may be accomplished as part of the type casting extensions of Leo.
The following code shows a string literal and its actual transformation into an
array of characters as well as possible array-like operations on strings:
concatenation and comparison.
```js
function main() -> bool {
// double quotes create char array from string
let hello: [char; 5] = "hello";
let world: [char; 5] = ['w','o','r','l','d'];
// string concatenation can be performed using array syntax
let hello_world: [char; 11] = [...hello, ' ', ...world];
// string comparison is also implemented via array type
return hello_world == "hello world";
}
```
## Format Strings ## Format Strings
@ -197,6 +248,38 @@ which will be interpreted as a format string
according to the semantics of console print calls. according to the semantics of console print calls.
The internal UTF-32 string will be translated to UTF-8 for output. The internal UTF-32 string will be translated to UTF-8 for output.
## Circuit Types for Character and String Operations
The operations on characters and lists described earlier, e.g. `is_ascii`,
are provided as static member functions of two new built-in or library circuit types `Char` and `String`.
Thus, an example call is `Char::is_ascii(c)`.
This seems a general good way to organize built-in or library operations,
and supports the use of the same name with different circuit types,
e.g. `Char::to_uppercase` and `String::to_uppercase`.
These circuit types could also include constants, e.g. for certain ASCII characters.
However, currently Leo does not support constants in circuit types,
so that would have to be added separately first.
These two circuit types are just meant to collect static member functions for characters and strings.
They are not meant to be the types of characters and strings:
as mentioned previously, `char` is a new scalar (not circuit) type (like `bool`, `address`, `u8`, etc.)
and there is no string type as such for now, but we use character arrays for strings.
In the future we may want all the Leo types to be circuit types of some sort,
but that is a separate feature that would have to be designed and developed independently.
## Input and Output of Literal Characters and Strings
Since UTF-8 is a standard encoding, it would make sense for
the literal characters and strings in the `.in` file
to be automatically converted to UTF-32 by the Leo compiler.
However, the size of a string can be confusing since multiple
Unicode code points can be composed into a single glyph which
then appears to be a single character. If a parameter of type `[char; 10]`
[if that is the syntax we decide on] is passed a literal string
of a different size, the error message should explain that the
size must be the number of codepoints needed to encode the string.
## Compilation to R1CS ## Compilation to R1CS
So far, the discussion has been independent from R1CS So far, the discussion has been independent from R1CS
@ -209,10 +292,10 @@ This section discusses R1CS compilation considerations
for this proposal for characters and strings. for this proposal for characters and strings.
Values of type `char` can be represented directly as field elements, Values of type `char` can be represented directly as field elements,
since the prime of the field is (much) larger than 10FFFFh. since the prime of the field is (much) larger than 10FFFF.
This is more efficient than using a bit representation of characters. This is more efficient than using a bit representation of characters.
By construction, field elements that represent `char` values By construction, field elements that represent `char` values
are never above 10FFFFh. are never above 10FFFF.
Note that `field` and `char` remain separate types in Leo: Note that `field` and `char` remain separate types in Leo:
it is only in the compilation to R1CS it is only in the compilation to R1CS
that everything is reduced to field elements. that everything is reduced to field elements.
@ -226,6 +309,35 @@ applies to strings without exception.
String literals are just syntactic sugar for String literals are just syntactic sugar for
suitable array inline construction expressions. suitable array inline construction expressions.
There are at least two approaches to implementing
ordering operations `<` and `<=` on `char` values.
Recalling that characters are represented as field values
that are (well) below `(p-1)/2` where `p` is the prime,
we can compare two field values `x` and `y`,
both below `(p-1)/2`, via the constraints
```
(2) (x - y) = (b0 + 2*b1 + 4*b2 + ...)
(b0) (1 - b0) = 0
(b1) (1 - b1) = 0
(b2) (1 - b2) = 0
...
```
that take the difference, double it, and convert to bits.
If `x >= y`, the difference is below `(p-1)/2`,
and doubling results in an even number below `p`,
with therefore `b0 = 0`.
If `x < y`, the difference is above `(p-1)/2` (when reduced modulo `p`),
and doubling results in an odd number when reduced modulo `p`,
with therefore `b0 = 1`.
Note that we need one variable and one constraint for every bit of `p`.
The other approach is to convert the `x` and `y` to bits
and compare them as integers;
in this case we only need 21 bits for each.
We need more analysis to determine which approach is more efficient.
The details of implementing other character and string operations in R1CS
will be fleshed out as each operation is added.
## Future Extensions ## Future Extensions
As alluded to in the section about design above, As alluded to in the section about design above,
@ -259,17 +371,18 @@ But the need to support characters and strings justifies the extra complexity.
With the ability of Leo programs to process strings, With the ability of Leo programs to process strings,
it may be useful to have external tools that convert Leo strings it may be useful to have external tools that convert Leo strings
to/from common formats, e.g. UTF-8. to/from common formats, e.g. UTF-8.
See the discussion of input files in the design section.
# Alternatives # Alternatives
We could avoid the new `char` type altogether, We could avoid the new `char` type altogether,
and instead, rely on the existing `u32` to represent Unicode code points, and instead, rely on the existing `u32` to represent Unicode code points,
and provide character-oriented operations on `u32` values. and provide character-oriented operations on `u32` values.
(Note that both `u8` and `u16` are too small for 10FFFFh, (Note that both `u8` and `u16` are too small for 10FFFF,
and that signed integer types include negative integers and that signed integer types include negative integers
which are not Unicode code points: which are not Unicode code points:
this makes `u32` the obvious choice.) this makes `u32` the obvious choice.)
However, many values of type `u32` are above 10FFFFh, However, many values of type `u32` are above 10FFFF,
and many operations on `u32` do not really make sense on code points. and many operations on `u32` do not really make sense on code points.
We would probably want a notation for character literals anyhow, We would probably want a notation for character literals anyhow,
which could be (arguably mis)used for non-character unsigned integers. which could be (arguably mis)used for non-character unsigned integers.

View File

@ -1,5 +1,5 @@
circuit PedersenHash { circuit PedersenHash {
parameters: [group; 256], parameters: [group; 256];
// Instantiates a Pedersen hash circuit // Instantiates a Pedersen hash circuit
function new(parameters: [group; 256]) -> Self { function new(parameters: [group; 256]) -> Self {

View File

@ -16,7 +16,7 @@
circuit SillySudoku { circuit SillySudoku {
// The starting grid values for the Sudoku puzzle. // The starting grid values for the Sudoku puzzle.
// Unset cells on the puzzle grid are set to 0. // Unset cells on the puzzle grid are set to 0.
puzzle_grid: [u8; (3, 3)], puzzle_grid: [u8; (3, 3)];
/** /**
* Returns true if a given Sudoku answer is correct. * Returns true if a given Sudoku answer is correct.

View File

@ -476,7 +476,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs.
whitespace = space / horizontal-tab / newline whitespace = space / horizontal-tab / newline
``` ```
Go to: _[space](#user-content-space), [newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab)_; Go to: _[newline](#user-content-newline), [space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab)_;
There are two kinds of comments in Leo, as in other languages. There are two kinds of comments in Leo, as in other languages.
@ -494,7 +494,7 @@ the ones used in the Java language reference.
comment = block-comment / end-of-line-comment comment = block-comment / end-of-line-comment
``` ```
Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_;
<a name="block-comment"></a> <a name="block-comment"></a>
@ -511,7 +511,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star
/ not-star rest-of-block-comment / not-star rest-of-block-comment
``` ```
Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star)_; Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star](#user-content-not-star)_;
<a name="rest-of-block-comment-after-star"></a> <a name="rest-of-block-comment-after-star"></a>
@ -521,7 +521,7 @@ rest-of-block-comment-after-star = "/"
/ not-star-or-slash rest-of-block-comment / not-star-or-slash rest-of-block-comment
``` ```
Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; Go to: _[not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_;
<a name="end-of-line-comment"></a> <a name="end-of-line-comment"></a>
@ -596,7 +596,7 @@ lowercase-letter = %x61-7A ; a-z
letter = uppercase-letter / lowercase-letter letter = uppercase-letter / lowercase-letter
``` ```
Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_; Go to: _[uppercase-letter](#user-content-uppercase-letter), [lowercase-letter](#user-content-lowercase-letter)_;
An identifier is a non-empty sequence of letters, digits, and underscores, An identifier is a non-empty sequence of letters, digits, and underscores,
@ -642,7 +642,7 @@ format-string-element = not-double-quote-or-open-brace
/ format-string-container / format-string-container
``` ```
Go to: _[format-string-container](#user-content-format-string-container), [not-double-quote-or-open-brace](#user-content-not-double-quote-or-open-brace), [not-double-quote-or-close-brace](#user-content-not-double-quote-or-close-brace)_; Go to: _[format-string-container](#user-content-format-string-container), [not-double-quote-or-close-brace](#user-content-not-double-quote-or-close-brace), [not-double-quote-or-open-brace](#user-content-not-double-quote-or-open-brace)_;
<a name="format-string"></a> <a name="format-string"></a>
@ -767,7 +767,7 @@ atomic-literal = untyped-literal
/ address-literal / address-literal
``` ```
Go to: _[product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal), [unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [address-literal](#user-content-address-literal)_; Go to: _[untyped-literal](#user-content-untyped-literal), [product-group-literal](#user-content-product-group-literal), [unsigned-literal](#user-content-unsigned-literal), [signed-literal](#user-content-signed-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [field-literal](#user-content-field-literal)_;
After defining the (mostly) alphanumeric tokens above, After defining the (mostly) alphanumeric tokens above,
@ -812,7 +812,7 @@ token = keyword
/ symbol / symbol
``` ```
Go to: _[package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [format-string](#user-content-format-string), [keyword](#user-content-keyword), [atomic-literal](#user-content-atomic-literal), [identifier](#user-content-identifier), [symbol](#user-content-symbol)_; Go to: _[keyword](#user-content-keyword), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [format-string](#user-content-format-string), [symbol](#user-content-symbol), [identifier](#user-content-identifier)_;
@ -848,7 +848,7 @@ signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128"
integer-type = unsigned-type / signed-type integer-type = unsigned-type / signed-type
``` ```
Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_;
The integer types, along with the field and group types, The integer types, along with the field and group types,
@ -869,7 +869,7 @@ group-type = %s"group"
arithmetic-type = integer-type / field-type / group-type arithmetic-type = integer-type / field-type / group-type
``` ```
Go to: _[integer-type](#user-content-integer-type), [field-type](#user-content-field-type), [group-type](#user-content-group-type)_; Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_;
The arithmetic types, along with the boolean and address types, The arithmetic types, along with the boolean and address types,
@ -890,7 +890,7 @@ address-type = %s"address"
scalar-type = boolean-type / arithmetic-type / address-type scalar-type = boolean-type / arithmetic-type / address-type
``` ```
Go to: _[arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type)_; Go to: _[address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type)_;
Circuit types are denoted by identifiers and the keyword `Self`. Circuit types are denoted by identifiers and the keyword `Self`.
@ -951,7 +951,7 @@ i.e. types whose values contain (sub-)values
aggregate-type = tuple-type / array-type / circuit-type aggregate-type = tuple-type / array-type / circuit-type
``` ```
Go to: _[tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type)_; Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_;
Scalar and aggregate types form all the types. Scalar and aggregate types form all the types.
@ -997,7 +997,7 @@ A literal is either an atomic one or an affine group literal.
literal = atomic-literal / affine-group-literal literal = atomic-literal / affine-group-literal
``` ```
Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_; Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_;
The following rule is not directly referenced in the rules for expressions The following rule is not directly referenced in the rules for expressions
@ -1039,7 +1039,7 @@ primary-expression = identifier
/ circuit-expression / circuit-expression
``` ```
Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [literal](#user-content-literal)_; Go to: _[expression](#user-content-expression), [literal](#user-content-literal), [identifier](#user-content-identifier), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [tuple-expression](#user-content-tuple-expression)_;
Tuple expressions construct tuples. Tuple expressions construct tuples.
@ -1100,7 +1100,7 @@ Go to: _[expression](#user-content-expression), [array-dimensions](#user-content
array-construction = array-inline-construction / array-repeat-construction array-construction = array-inline-construction / array-repeat-construction
``` ```
Go to: _[array-repeat-construction](#user-content-array-repeat-construction), [array-inline-construction](#user-content-array-inline-construction)_; Go to: _[array-inline-construction](#user-content-array-inline-construction), [array-repeat-construction](#user-content-array-repeat-construction)_;
<a name="array-expression"></a> <a name="array-expression"></a>
@ -1128,7 +1128,7 @@ circuit-construction = circuit-type "{"
"}" "}"
``` ```
Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_;
<a name="circuit-inline-element"></a> <a name="circuit-inline-element"></a>
@ -1187,7 +1187,7 @@ postfix-expression = primary-expression
/ postfix-expression "[" [expression] ".." [expression] "]" / postfix-expression "[" [expression] ".." [expression] "]"
``` ```
Go to: _[function-arguments](#user-content-function-arguments), [postfix-expression](#user-content-postfix-expression), [natural](#user-content-natural), [circuit-type](#user-content-circuit-type), [expression](#user-content-expression), [identifier](#user-content-identifier), [primary-expression](#user-content-primary-expression)_; Go to: _[expression](#user-content-expression), [natural](#user-content-natural), [identifier](#user-content-identifier), [primary-expression](#user-content-primary-expression), [circuit-type](#user-content-circuit-type), [function-arguments](#user-content-function-arguments), [postfix-expression](#user-content-postfix-expression)_;
Unary operators have the highest operator precedence. Unary operators have the highest operator precedence.
@ -1201,7 +1201,7 @@ unary-expression = postfix-expression
/ "-" unary-expression / "-" unary-expression
``` ```
Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_; Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_;
Next in the operator precedence is exponentiation, Next in the operator precedence is exponentiation,
@ -1215,7 +1215,7 @@ exponential-expression = unary-expression
/ unary-expression "**" exponential-expression / unary-expression "**" exponential-expression
``` ```
Go to: _[unary-expression](#user-content-unary-expression), [exponential-expression](#user-content-exponential-expression)_; Go to: _[exponential-expression](#user-content-exponential-expression), [unary-expression](#user-content-unary-expression)_;
Next in precedence come multiplication and division, both left-associative. Next in precedence come multiplication and division, both left-associative.
@ -1227,7 +1227,7 @@ multiplicative-expression = exponential-expression
/ multiplicative-expression "/" exponential-expression / multiplicative-expression "/" exponential-expression
``` ```
Go to: _[exponential-expression](#user-content-exponential-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [exponential-expression](#user-content-exponential-expression)_;
Then there are addition and subtraction, both left-assocative. Then there are addition and subtraction, both left-assocative.
@ -1239,7 +1239,7 @@ additive-expression = multiplicative-expression
/ additive-expression "-" multiplicative-expression / additive-expression "-" multiplicative-expression
``` ```
Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_;
Next in the precedence order are ordering relations. Next in the precedence order are ordering relations.
@ -1267,7 +1267,7 @@ equality-expression = ordering-expression
/ equality-expression "!=" ordering-expression / equality-expression "!=" ordering-expression
``` ```
Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_;
Next come conjunctive expressions, left-associative. Next come conjunctive expressions, left-associative.
@ -1289,7 +1289,7 @@ disjunctive-expression = conjunctive-expression
/ disjunctive-expression "||" conjunctive-expression / disjunctive-expression "||" conjunctive-expression
``` ```
Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_;
Finally we have conditional expressions. Finally we have conditional expressions.
@ -1302,7 +1302,7 @@ conditional-expression = disjunctive-expression
":" conditional-expression ":" conditional-expression
``` ```
Go to: _[expression](#user-content-expression), [conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; Go to: _[expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression)_;
Those above are all the expressions. Those above are all the expressions.
@ -1335,7 +1335,7 @@ statement = expression-statement
/ block / block
``` ```
Go to: _[expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block), [loop-statement](#user-content-loop-statement), [constant-declaration](#user-content-constant-declaration), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [variable-declaration](#user-content-variable-declaration)_; Go to: _[block](#user-content-block), [constant-declaration](#user-content-constant-declaration), [variable-declaration](#user-content-variable-declaration), [return-statement](#user-content-return-statement), [expression-statement](#user-content-expression-statement), [loop-statement](#user-content-loop-statement), [conditional-statement](#user-content-conditional-statement), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement)_;
<a name="block"></a> <a name="block"></a>
@ -1378,7 +1378,7 @@ variable-declaration = %s"let" identifier-or-identifiers [ ":" type ]
"=" expression ";" "=" expression ";"
``` ```
Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; Go to: _[type](#user-content-type), [expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_;
<a name="constant-declaration"></a> <a name="constant-declaration"></a>
@ -1387,7 +1387,7 @@ constant-declaration = %s"const" identifier-or-identifiers [ ":" type ]
"=" expression ";" "=" expression ";"
``` ```
Go to: _[expression](#user-content-expression), [type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type), [expression](#user-content-expression)_;
<a name="identifier-or-identifiers"></a> <a name="identifier-or-identifiers"></a>
@ -1420,7 +1420,7 @@ conditional-statement = branch
/ branch %s"else" conditional-statement / branch %s"else" conditional-statement
``` ```
Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_; Go to: _[branch](#user-content-branch), [block](#user-content-block), [conditional-statement](#user-content-conditional-statement)_;
A loop statement implicitly defines a loop variable A loop statement implicitly defines a loop variable
@ -1432,7 +1432,7 @@ The body is a block.
loop-statement = %s"for" identifier %s"in" expression ".." expression block loop-statement = %s"for" identifier %s"in" expression ".." expression block
``` ```
Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [block](#user-content-block)_; Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier), [block](#user-content-block)_;
An assignment statement is straightforward. An assignment statement is straightforward.
@ -1476,7 +1476,7 @@ console-call = assert-call
/ print-call / print-call
``` ```
Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_; Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_;
<a name="assert-call"></a> <a name="assert-call"></a>
@ -1535,7 +1535,7 @@ function-declaration = *annotation %s"function" identifier
block block
``` ```
Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [type](#user-content-type)_; Go to: _[type](#user-content-type), [block](#user-content-block), [identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters)_;
<a name="function-parameters"></a> <a name="function-parameters"></a>
@ -1545,7 +1545,7 @@ function-parameters = self-parameter
/ function-inputs / function-inputs
``` ```
Go to: _[self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs)_; Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter)_;
<a name="self-parameter"></a> <a name="self-parameter"></a>
@ -1566,24 +1566,15 @@ Go to: _[function-input](#user-content-function-input)_;
function-input = [ %s"const" ] identifier ":" type function-input = [ %s"const" ] identifier ":" type
``` ```
Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
A circuit member variable declaration consists of an identifier and a type. A circuit member variable declaration consists of an identifier and a type.
A circuit member function declaration consists of a function declaration. A circuit member function declaration consists of a function declaration.
<a name="member-declaration"></a> <a name="member-variable-declarations"></a>
```abnf ```abnf
member-declaration = member-variable-declaration member-variable-declarations = *(identifier ":" type ( "," / ";" )) identifier ":" type ( [ "," ] / ";" )
/ member-function-declaration
```
Go to: _[member-function-declaration](#user-content-member-function-declaration), [member-variable-declaration](#user-content-member-variable-declaration)_;
<a name="member-variable-declaration"></a>
```abnf
member-variable-declaration = identifier ":" type
``` ```
Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
@ -1603,10 +1594,10 @@ as consisting of member variables and functions.
<a name="circuit-declaration"></a> <a name="circuit-declaration"></a>
```abnf ```abnf
circuit-declaration = *annotation %s"circuit" identifier circuit-declaration = *annotation %s"circuit" identifier
"{" member-declaration *( "," member-declaration ) "}" "{" [ member-variable-declarations ] *member-function-declaration "}"
``` ```
Go to: _[identifier](#user-content-identifier), [member-declaration](#user-content-member-declaration)_; Go to: _[member-variable-declarations](#user-content-member-variable-declarations), [identifier](#user-content-identifier)_;
An import declaration consists of the `import` keyword An import declaration consists of the `import` keyword
@ -1621,10 +1612,10 @@ to be followed by a comma, for convenience.
<a name="import-declaration"></a> <a name="import-declaration"></a>
```abnf ```abnf
import-declaration = %s"import" package-path ";" import-declaration = %s"import" package-name "." package-path ";"
``` ```
Go to: _[package-path](#user-content-package-path)_; Go to: _[package-path](#user-content-package-path), [package-name](#user-content-package-name)_;
<a name="package-path"></a> <a name="package-path"></a>
@ -1635,7 +1626,7 @@ package-path = "*"
/ "(" package-path *( "," package-path ) [","] ")" / "(" package-path *( "," package-path ) [","] ")"
``` ```
Go to: _[identifier](#user-content-identifier), [package-path](#user-content-package-path), [package-name](#user-content-package-name)_; Go to: _[package-name](#user-content-package-name), [identifier](#user-content-identifier), [package-path](#user-content-package-path)_;
Finally, we define a file as a sequence of zero or more declarations. Finally, we define a file as a sequence of zero or more declarations.
@ -1650,7 +1641,7 @@ declaration = import-declaration
/ constant-declaration / constant-declaration
``` ```
Go to: _[constant-declaration](#user-content-constant-declaration), [import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_; Go to: _[function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration), [constant-declaration](#user-content-constant-declaration)_;
<a name="file"></a> <a name="file"></a>

View File

@ -942,21 +942,35 @@ function-inputs = function-input *( "," function-input )
function-input = [ %s"const" ] identifier ":" type function-input = [ %s"const" ] identifier ":" type
; A circuit member variable declaration consists of an identifier and a type. ; A circuit member variable declaration consists of
; an identifier and a type, terminated by semicolon.
; For backward compatibility,
; member variable declarations may be alternatively followed by commas,
; and the last one may not be followed by anything:
; these are deprecated, and will be eventually removed,
; leaving only mandatory semicolons.
; Note that there is no rule for a single `member-variable-declaration`,
; but instead one for a sequence of them;
; see the rule `circuit-declaration`.
member-variable-declarations = *( identifier ":" type ( "," / ";" ) )
identifier ":" type ( [ "," ] / ";" )
; A circuit member function declaration consists of a function declaration. ; A circuit member function declaration consists of a function declaration.
member-declaration = member-variable-declaration
/ member-function-declaration
member-variable-declaration = identifier ":" type
member-function-declaration = function-declaration member-function-declaration = function-declaration
; A circuit declaration defines a circuit type, ; A circuit declaration defines a circuit type,
; as consisting of member variables and functions. ; as consisting of member variables and functions.
; To more simply accommodate the backward compatibility
; described for the rule `member-variable-declarations`,
; all the member variables must precede all the member functions;
; this may be relaxed after the backward compatibility is removed,
; allowing member variables and member functions to be intermixed.
circuit-declaration = *annotation %s"circuit" identifier circuit-declaration = *annotation %s"circuit" identifier
"{" member-declaration *( "," member-declaration ) "}" "{" [ member-variable-declarations ]
*member-function-declaration "}"
; An import declaration consists of the `import` keyword ; An import declaration consists of the `import` keyword
; followed by a package path, which may be one of the following: ; followed by a package path, which may be one of the following:
@ -967,8 +981,12 @@ circuit-declaration = *annotation %s"circuit" identifier
; which are "fan out" of the initial path. ; which are "fan out" of the initial path.
; Note that we allow the last element of the parenthesized list ; Note that we allow the last element of the parenthesized list
; to be followed by a comma, for convenience. ; to be followed by a comma, for convenience.
; The package path in the import declaration must start with a package name
; (e.g. it cannot be a `*`):
; the rule for import declaration expresses this requirement
; by using an explicit package name before the package path.
import-declaration = %s"import" package-path ";" import-declaration = %s"import" package-name "." package-path ";"
package-path = "*" package-path = "*"
/ identifier [ %s"as" identifier ] / identifier [ %s"as" identifier ]

View File

@ -6,260 +6,260 @@ function main() {
} }
circuit Foo { circuit Foo {
x0: u8, x0: u8;
x1: u8, x1: u8;
x2: u8, x2: u8;
x3: u8, x3: u8;
x4: u8, x4: u8;
x5: u8, x5: u8;
x6: u8, x6: u8;
x7: u8, x7: u8;
x8: u8, x8: u8;
x9: u8, x9: u8;
x10: u8, x10: u8;
x11: u8, x11: u8;
x12: u8, x12: u8;
x13: u8, x13: u8;
x14: u8, x14: u8;
x15: u8, x15: u8;
x16: u8, x16: u8;
x17: u8, x17: u8;
x18: u8, x18: u8;
x19: u8, x19: u8;
x20: u8, x20: u8;
x21: u8, x21: u8;
x22: u8, x22: u8;
x23: u8, x23: u8;
x24: u8, x24: u8;
x25: u8, x25: u8;
x26: u8, x26: u8;
x27: u8, x27: u8;
x28: u8, x28: u8;
x29: u8, x29: u8;
x30: u8, x30: u8;
x31: u8, x31: u8;
x32: u8, x32: u8;
x33: u8, x33: u8;
x34: u8, x34: u8;
x35: u8, x35: u8;
x36: u8, x36: u8;
x37: u8, x37: u8;
x38: u8, x38: u8;
x39: u8, x39: u8;
x40: u8, x40: u8;
x41: u8, x41: u8;
x42: u8, x42: u8;
x43: u8, x43: u8;
x44: u8, x44: u8;
x45: u8, x45: u8;
x46: u8, x46: u8;
x47: u8, x47: u8;
x48: u8, x48: u8;
x49: u8, x49: u8;
x50: u8, x50: u8;
x51: u8, x51: u8;
x52: u8, x52: u8;
x53: u8, x53: u8;
x54: u8, x54: u8;
x55: u8, x55: u8;
x56: u8, x56: u8;
x57: u8, x57: u8;
x58: u8, x58: u8;
x59: u8, x59: u8;
x60: u8, x60: u8;
x61: u8, x61: u8;
x62: u8, x62: u8;
x63: u8, x63: u8;
x64: u8, x64: u8;
x65: u8, x65: u8;
x66: u8, x66: u8;
x67: u8, x67: u8;
x68: u8, x68: u8;
x69: u8, x69: u8;
x70: u8, x70: u8;
x71: u8, x71: u8;
x72: u8, x72: u8;
x73: u8, x73: u8;
x74: u8, x74: u8;
x75: u8, x75: u8;
x76: u8, x76: u8;
x77: u8, x77: u8;
x78: u8, x78: u8;
x79: u8, x79: u8;
x80: u8, x80: u8;
x81: u8, x81: u8;
x82: u8, x82: u8;
x83: u8, x83: u8;
x84: u8, x84: u8;
x85: u8, x85: u8;
x86: u8, x86: u8;
x87: u8, x87: u8;
x88: u8, x88: u8;
x89: u8, x89: u8;
x90: u8, x90: u8;
x91: u8, x91: u8;
x92: u8, x92: u8;
x93: u8, x93: u8;
x94: u8, x94: u8;
x95: u8, x95: u8;
x96: u8, x96: u8;
x97: u8, x97: u8;
x98: u8, x98: u8;
x99: u8, x99: u8;
x100: u8, x100: u8;
x101: u8, x101: u8;
x102: u8, x102: u8;
x103: u8, x103: u8;
x104: u8, x104: u8;
x105: u8, x105: u8;
x106: u8, x106: u8;
x107: u8, x107: u8;
x108: u8, x108: u8;
x109: u8, x109: u8;
x110: u8, x110: u8;
x111: u8, x111: u8;
x112: u8, x112: u8;
x113: u8, x113: u8;
x114: u8, x114: u8;
x115: u8, x115: u8;
x116: u8, x116: u8;
x117: u8, x117: u8;
x118: u8, x118: u8;
x119: u8, x119: u8;
x120: u8, x120: u8;
x121: u8, x121: u8;
x122: u8, x122: u8;
x123: u8, x123: u8;
x124: u8, x124: u8;
x125: u8, x125: u8;
x126: u8, x126: u8;
x127: u8, x127: u8;
x128: u8, x128: u8;
x129: u8, x129: u8;
x130: u8, x130: u8;
x131: u8, x131: u8;
x132: u8, x132: u8;
x133: u8, x133: u8;
x134: u8, x134: u8;
x135: u8, x135: u8;
x136: u8, x136: u8;
x137: u8, x137: u8;
x138: u8, x138: u8;
x139: u8, x139: u8;
x140: u8, x140: u8;
x141: u8, x141: u8;
x142: u8, x142: u8;
x143: u8, x143: u8;
x144: u8, x144: u8;
x145: u8, x145: u8;
x146: u8, x146: u8;
x147: u8, x147: u8;
x148: u8, x148: u8;
x149: u8, x149: u8;
x150: u8, x150: u8;
x151: u8, x151: u8;
x152: u8, x152: u8;
x153: u8, x153: u8;
x154: u8, x154: u8;
x155: u8, x155: u8;
x156: u8, x156: u8;
x157: u8, x157: u8;
x158: u8, x158: u8;
x159: u8, x159: u8;
x160: u8, x160: u8;
x161: u8, x161: u8;
x162: u8, x162: u8;
x163: u8, x163: u8;
x164: u8, x164: u8;
x165: u8, x165: u8;
x166: u8, x166: u8;
x167: u8, x167: u8;
x168: u8, x168: u8;
x169: u8, x169: u8;
x170: u8, x170: u8;
x171: u8, x171: u8;
x172: u8, x172: u8;
x173: u8, x173: u8;
x174: u8, x174: u8;
x175: u8, x175: u8;
x176: u8, x176: u8;
x177: u8, x177: u8;
x178: u8, x178: u8;
x179: u8, x179: u8;
x180: u8, x180: u8;
x181: u8, x181: u8;
x182: u8, x182: u8;
x183: u8, x183: u8;
x184: u8, x184: u8;
x185: u8, x185: u8;
x186: u8, x186: u8;
x187: u8, x187: u8;
x188: u8, x188: u8;
x189: u8, x189: u8;
x190: u8, x190: u8;
x191: u8, x191: u8;
x192: u8, x192: u8;
x193: u8, x193: u8;
x194: u8, x194: u8;
x195: u8, x195: u8;
x196: u8, x196: u8;
x197: u8, x197: u8;
x198: u8, x198: u8;
x199: u8, x199: u8;
x200: u8, x200: u8;
x201: u8, x201: u8;
x202: u8, x202: u8;
x203: u8, x203: u8;
x204: u8, x204: u8;
x205: u8, x205: u8;
x206: u8, x206: u8;
x207: u8, x207: u8;
x208: u8, x208: u8;
x209: u8, x209: u8;
x210: u8, x210: u8;
x211: u8, x211: u8;
x212: u8, x212: u8;
x213: u8, x213: u8;
x214: u8, x214: u8;
x215: u8, x215: u8;
x216: u8, x216: u8;
x217: u8, x217: u8;
x218: u8, x218: u8;
x219: u8, x219: u8;
x220: u8, x220: u8;
x221: u8, x221: u8;
x222: u8, x222: u8;
x223: u8, x223: u8;
x224: u8, x224: u8;
x225: u8, x225: u8;
x226: u8, x226: u8;
x227: u8, x227: u8;
x228: u8, x228: u8;
x229: u8, x229: u8;
x230: u8, x230: u8;
x231: u8, x231: u8;
x232: u8, x232: u8;
x233: u8, x233: u8;
x234: u8, x234: u8;
x235: u8, x235: u8;
x236: u8, x236: u8;
x237: u8, x237: u8;
x238: u8, x238: u8;
x239: u8, x239: u8;
x240: u8, x240: u8;
x241: u8, x241: u8;
x242: u8, x242: u8;
x243: u8, x243: u8;
x244: u8, x244: u8;
x245: u8, x245: u8;
x246: u8, x246: u8;
x247: u8, x247: u8;
x248: u8, x248: u8;
x249: u8, x249: u8;
x250: u8, x250: u8;
x251: u8, x251: u8;
x252: u8, x252: u8;
x253: u8, x253: u8;
x254: u8, x254: u8;
x255: u8 x255: u8;
} }

View File

@ -48,6 +48,10 @@ impl SyntaxError {
SyntaxError::Error(FormattedError::new_from_span(message, span)) SyntaxError::Error(FormattedError::new_from_span(message, span))
} }
pub fn invalid_import_list(span: &Span) -> Self {
Self::new_from_span("Cannot import empty list".to_string(), span)
}
pub fn unexpected_eof(span: &Span) -> Self { pub fn unexpected_eof(span: &Span) -> Self {
Self::new_from_span("unexpected EOF".to_string(), span) Self::new_from_span("unexpected EOF".to_string(), span)
} }
@ -74,6 +78,13 @@ impl SyntaxError {
) )
} }
pub fn mixed_commas_and_semicolons(span: &Span) -> Self {
Self::new_from_span(
"Cannot mix use of commas and semi-colons for circuit member variable declarations.".to_string(),
span,
)
}
pub fn unexpected_ident(got: &str, expected: &[&str], span: &Span) -> Self { pub fn unexpected_ident(got: &str, expected: &[&str], span: &Span) -> Self {
Self::new_from_span( Self::new_from_span(
format!( format!(

View File

@ -66,6 +66,13 @@ impl ParserContext {
SyntaxError::unexpected_eof(&self.end_span) SyntaxError::unexpected_eof(&self.end_span)
} }
///
/// Returns a reference to the next next token or error if it does not exist.
///
pub fn peek_next(&self) -> SyntaxResult<&SpannedToken> {
self.tokens.get(self.tokens.len() - 2).ok_or_else(|| self.eof())
}
/// ///
/// Returns a reference to the next token or error if it does not exist. /// Returns a reference to the next token or error if it does not exist.
/// ///

View File

@ -136,7 +136,7 @@ impl ParserContext {
/// Returns a vector of [`PackageAccess`] AST nodes if the next tokens represent package access /// Returns a vector of [`PackageAccess`] AST nodes if the next tokens represent package access
/// expressions within an import statement. /// expressions within an import statement.
/// ///
pub fn parse_package_accesses(&mut self) -> SyntaxResult<Vec<PackageAccess>> { pub fn parse_package_accesses(&mut self, span: &Span) -> SyntaxResult<Vec<PackageAccess>> {
let mut out = Vec::new(); let mut out = Vec::new();
self.expect(Token::LeftParen)?; self.expect(Token::LeftParen)?;
while self.eat(Token::RightParen).is_none() { while self.eat(Token::RightParen).is_none() {
@ -147,6 +147,11 @@ impl ParserContext {
break; break;
} }
} }
if out.is_empty() {
return Err(SyntaxError::invalid_import_list(span));
}
Ok(out) Ok(out)
} }
@ -156,7 +161,7 @@ impl ParserContext {
/// ///
pub fn parse_package_access(&mut self) -> SyntaxResult<PackageAccess> { pub fn parse_package_access(&mut self) -> SyntaxResult<PackageAccess> {
if let Some(SpannedToken { span, .. }) = self.eat(Token::Mul) { if let Some(SpannedToken { span, .. }) = self.eat(Token::Mul) {
Ok(PackageAccess::Star(span)) Ok(PackageAccess::Star { span })
} else { } else {
let name = self.expect_ident()?; let name = self.expect_ident()?;
if self.peek_token().as_ref() == &Token::Dot { if self.peek_token().as_ref() == &Token::Dot {
@ -247,7 +252,7 @@ impl ParserContext {
let package_name = self.parse_package_name()?; let package_name = self.parse_package_name()?;
self.expect(Token::Dot)?; self.expect(Token::Dot)?;
if self.peek()?.token == Token::LeftParen { if self.peek()?.token == Token::LeftParen {
let accesses = self.parse_package_accesses()?; let accesses = self.parse_package_accesses(&package_name.span)?;
Ok(PackageOrPackages::Packages(Packages { Ok(PackageOrPackages::Packages(Packages {
span: &package_name.span + accesses.last().map(|x| x.span()).unwrap_or(&package_name.span), span: &package_name.span + accesses.last().map(|x| x.span()).unwrap_or(&package_name.span),
name: package_name, name: package_name,
@ -280,18 +285,82 @@ impl ParserContext {
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable /// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable
/// or circuit member function. /// or circuit member function.
/// ///
pub fn parse_circuit_member(&mut self) -> SyntaxResult<CircuitMember> { pub fn parse_circuit_declaration(&mut self) -> SyntaxResult<Vec<CircuitMember>> {
let mut members = Vec::new();
let peeked = &self.peek()?.token; let peeked = &self.peek()?.token;
if peeked == &Token::Function || peeked == &Token::At { let mut last_variable = peeked == &Token::Function || peeked == &Token::At;
let function = self.parse_function_declaration()?; let (mut semi_colons, mut commas) = (false, false);
Ok(CircuitMember::CircuitFunction(function.1)) while self.eat(Token::RightCurly).is_none() {
if !last_variable {
let (variable, last) = self.parse_member_variable_declaration()?;
members.push(variable);
let peeked = &self.peek()?;
if peeked.token == Token::Semicolon {
if commas {
return Err(SyntaxError::mixed_commas_and_semicolons(&peeked.span));
}
semi_colons = true;
self.expect(Token::Semicolon)?;
} else { } else {
// circuit variable if semi_colons {
return Err(SyntaxError::mixed_commas_and_semicolons(&peeked.span));
}
commas = true;
self.eat(Token::Comma);
}
if last {
last_variable = last;
}
} else {
let function = self.parse_member_function_declaration()?;
members.push(function);
}
}
Ok(members)
}
///
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable.
///
pub fn parse_member_variable_declaration(&mut self) -> SyntaxResult<(CircuitMember, bool)> {
let name = self.expect_ident()?; let name = self.expect_ident()?;
self.expect(Token::Colon)?; self.expect(Token::Colon)?;
let type_ = self.parse_type()?.0; let type_ = self.parse_type()?.0;
self.eat(Token::Comma);
Ok(CircuitMember::CircuitVariable(name, type_)) let peeked = &self.peek()?.token;
if peeked == &Token::Function || peeked == &Token::At || peeked == &Token::RightCurly {
return Ok((CircuitMember::CircuitVariable(name, type_), true));
} else if peeked == &Token::Comma || peeked == &Token::Semicolon {
let peeked = &self.peek_next()?.token;
if peeked == &Token::Function || peeked == &Token::At || peeked == &Token::RightCurly {
return Ok((CircuitMember::CircuitVariable(name, type_), true));
}
}
Ok((CircuitMember::CircuitVariable(name, type_), false))
}
///
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member function.
///
pub fn parse_member_function_declaration(&mut self) -> SyntaxResult<CircuitMember> {
let peeked = &self.peek()?;
let peeked_token = &peeked.token;
if peeked_token == &Token::Function || peeked_token == &Token::At {
let function = self.parse_function_declaration()?;
Ok(CircuitMember::CircuitFunction(function.1))
} else {
Err(SyntaxError::unexpected(
peeked_token,
&[Token::Function, Token::At],
&peeked.span,
))
} }
} }
@ -303,11 +372,8 @@ impl ParserContext {
self.expect(Token::Circuit)?; self.expect(Token::Circuit)?;
let name = self.expect_ident()?; let name = self.expect_ident()?;
self.expect(Token::LeftCurly)?; self.expect(Token::LeftCurly)?;
let mut members = Vec::new(); let members = self.parse_circuit_declaration()?;
while self.eat(Token::RightCurly).is_none() {
let member = self.parse_circuit_member()?;
members.push(member);
}
Ok((name.clone(), Circuit { Ok((name.clone(), Circuit {
circuit_name: name, circuit_name: name,
members, members,

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function use_a(const self) -> u8 { function use_a(const self) -> u8 {
return self.a + 1; return self.a + 1;

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(const self, new: u8) { function set_a(const self, new: u8) {
self.a = new; self.a = new;

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
x: u8 x: u8;
} }
function main() { function main() {

View File

@ -8,7 +8,7 @@ inputs:
*/ */
circuit Foo { circuit Foo {
foo: u32, foo: u32;
function bar() -> u32 { function bar() -> u32 {
return 1u32; return 1u32;

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
function main() { function main() {

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}
} }

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function bar() {} function bar() {}

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(mut self, new: u8) { function set_a(mut self, new: u8) {
self.a = new; self.a = new;

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(mut self, condition: bool, new: u8) { function set_a(mut self, condition: bool, new: u8) {
if condition { if condition {

View File

@ -10,7 +10,7 @@ function main() {
} }
circuit Foo { circuit Foo {
a: u32 a: u32;
function bar(mut self) { function bar(mut self) {
if true { if true {

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
function set_a(self, new: u8) { function set_a(self, new: u8) {
self.a = new; self.a = new;

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
} }
function main() { function main() {

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
a: u8, a: u8;
} }
function main() { function main() {

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit TestMe { circuit TestMe {
x: u8, x: u8;
function test_me(mut self) -> u8 { function test_me(mut self) -> u8 {
self.x += 1; self.x += 1;

View File

@ -11,7 +11,7 @@ inputs:
*/ */
circuit PedersenHash { circuit PedersenHash {
parameters: [u32; 512] parameters: [u32; 512];
function new(parameters: [u32; 512]) -> Self { function new(parameters: [u32; 512]) -> Self {
return Self { parameters: parameters }; return Self { parameters: parameters };

View File

@ -4,7 +4,7 @@ expectation: Pass
*/ */
circuit Foo { circuit Foo {
f: u32, f: u32;
function bar(self) -> u32 { function bar(self) -> u32 {
return self.f; return self.f;

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
f: u32, f: u32;
function bar() -> u32 { function bar() -> u32 {
return f; return f;

View File

@ -1,3 +1,3 @@
circuit Bat { circuit Bat {
t: u32 t: u32;
} }

View File

@ -1,7 +1,9 @@
circuit Baz { circuit Baz {
z: u32 z: u32;
} }
circuit Bazzar { circuit Bazzar {
a: u32 a: u32;
} }
const ONE: u8 = 1;

View File

@ -1,3 +1,3 @@
circuit Bar { circuit Bar {
r: u32 r: u32;
} }

View File

@ -1,3 +1,3 @@
circuit Car { circuit Car {
c: u32 c: u32;
} }

View File

@ -4,7 +4,7 @@ expectation: Fail
*/ */
circuit Foo { circuit Foo {
x: u32 x: u32;
} }
// const variable is immutable // const variable is immutable

View File

@ -13,7 +13,7 @@ outputs:
- "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" x: u32,\\\"}\"}" - "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" x: u32,\\\"}\"}"
- IntegerType: U32 - IntegerType: U32
- CircuitVariable: - CircuitVariable:
- "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" y: u32,\\\"}\"}" - "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" y: u32\\\"}\"}"
- IntegerType: U32 - IntegerType: U32
- CircuitFunction: - CircuitFunction:
annotations: [] annotations: []

View File

@ -10,10 +10,10 @@ outputs:
circuit_name: "{\"name\":\"X\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"circuit X {\\\"}\"}" circuit_name: "{\"name\":\"X\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"circuit X {\\\"}\"}"
members: members:
- CircuitVariable: - CircuitVariable:
- "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" x: u32,\\\"}\"}" - "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" x: u32;\\\"}\"}"
- IntegerType: U32 - IntegerType: U32
- CircuitVariable: - CircuitVariable:
- "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" y: u32,\\\"}\"}" - "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\" y: u32;\\\"}\"}"
- IntegerType: U32 - IntegerType: U32
global_consts: {} global_consts: {}
functions: {} functions: {}

View File

@ -0,0 +1,5 @@
---
namespace: Parse
expectation: Fail
outputs:
- " --> test:10:11\n |\n 10 | y: u32;\n | ^\n |\n = Cannot mix use of commas and semi-colons for circuit member variable declarations."

View File

@ -0,0 +1,5 @@
---
namespace: Parse
expectation: Fail
outputs:
- " --> test:3:8\n |\n 3 | import a.();\n | ^\n |\n = Cannot import empty list"

View File

@ -10,6 +10,7 @@ outputs:
name: "{\"name\":\"test-import\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":8,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import test-import.*; // local import\\\"}\"}" name: "{\"name\":\"test-import\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":8,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import test-import.*; // local import\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 3 line_start: 3
line_stop: 3 line_stop: 3
col_start: 20 col_start: 20
@ -35,6 +36,7 @@ outputs:
name: "{\"name\":\"bar\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":8,\\\"col_stop\\\":11,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.*; // imports directory import\\\"}\"}" name: "{\"name\":\"bar\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":8,\\\"col_stop\\\":11,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.*; // imports directory import\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 5 line_start: 5
line_stop: 5 line_stop: 5
col_start: 12 col_start: 12
@ -63,6 +65,7 @@ outputs:
name: "{\"name\":\"baz\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.baz.*; // imports directory import\\\"}\"}" name: "{\"name\":\"baz\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.baz.*; // imports directory import\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 6 line_start: 6
line_stop: 6 line_stop: 6
col_start: 16 col_start: 16
@ -101,6 +104,7 @@ outputs:
name: "{\"name\":\"bat\",\"span\":\"{\\\"line_start\\\":7,\\\"line_stop\\\":7,\\\"col_start\\\":16,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.bat.bat.*; // imports directory import\\\"}\"}" name: "{\"name\":\"bat\",\"span\":\"{\\\"line_start\\\":7,\\\"line_stop\\\":7,\\\"col_start\\\":16,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import bar.bat.bat.*; // imports directory import\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 7 line_start: 7
line_stop: 7 line_stop: 7
col_start: 20 col_start: 20
@ -140,6 +144,7 @@ outputs:
name: "{\"name\":\"car\",\"span\":\"{\\\"line_start\\\":8,\\\"line_stop\\\":8,\\\"col_start\\\":8,\\\"col_stop\\\":11,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import car.*; // imports directory import\\\"}\"}" name: "{\"name\":\"car\",\"span\":\"{\\\"line_start\\\":8,\\\"line_stop\\\":8,\\\"col_start\\\":8,\\\"col_stop\\\":11,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import car.*; // imports directory import\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 8 line_start: 8
line_stop: 8 line_stop: 8
col_start: 12 col_start: 12

View File

@ -10,6 +10,7 @@ outputs:
name: "{\"name\":\"test-import\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":8,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import test-import.*;\\\"}\"}" name: "{\"name\":\"test-import\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":8,\\\"col_stop\\\":19,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"import test-import.*;\\\"}\"}"
access: access:
Star: Star:
span:
line_start: 3 line_start: 3
line_stop: 3 line_stop: 3
col_start: 20 col_start: 20

View File

@ -5,7 +5,7 @@ expectation: Pass
circuit X { circuit X {
x: u32, x: u32,
y: u32, y: u32
function x() { function x() {
return (); return ();
} }

View File

@ -4,6 +4,6 @@ expectation: Pass
*/ */
circuit X { circuit X {
x: u32, x: u32;
y: u32, y: u32;
} }

View File

@ -0,0 +1,14 @@
/*
namespace: Parse
expectation: Fail
*/
circuit X {
x: u32
y: u32
}
circuit X {
x: u32,
y: u32;
}

View File

@ -0,0 +1,6 @@
/*
namespace: Parse
expectation: Fail
*/
import a.();