mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-10-12 06:08:57 +03:00
Merge branch 'master' into compiler-tests
This commit is contained in:
commit
6bb14425fd
@ -172,6 +172,16 @@ impl AsgConvertError {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn invalid_const_assign(name: &str, span: &Span) -> Self {
|
||||||
|
Self::new_from_span(
|
||||||
|
format!(
|
||||||
|
"failed to create const variable(s) '{}' with non constant values.",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn duplicate_function_definition(name: &str, span: &Span) -> Self {
|
pub fn duplicate_function_definition(name: &str, span: &Span) -> Self {
|
||||||
Self::new_from_span(
|
Self::new_from_span(
|
||||||
format!("a function named \"{}\" already exists in this scope", name),
|
format!("a function named \"{}\" already exists in this scope", name),
|
||||||
|
@ -75,6 +75,17 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
|
|||||||
|
|
||||||
let value = <&Expression<'a>>::from_ast(scope, &statement.value, type_.clone().map(Into::into))?;
|
let value = <&Expression<'a>>::from_ast(scope, &statement.value, type_.clone().map(Into::into))?;
|
||||||
|
|
||||||
|
if matches!(statement.declaration_type, leo_ast::Declare::Const) && !value.is_consty() {
|
||||||
|
let var_names = statement
|
||||||
|
.variable_names
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ,");
|
||||||
|
|
||||||
|
return Err(AsgConvertError::invalid_const_assign(&var_names, &statement.span));
|
||||||
|
}
|
||||||
|
|
||||||
let type_ = type_.or_else(|| value.get_type());
|
let type_ = type_.or_else(|| value.get_type());
|
||||||
|
|
||||||
let mut output_types = vec![];
|
let mut output_types = vec![];
|
||||||
|
@ -2,7 +2,7 @@ function main(s: bool, c: address) {
|
|||||||
const a = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
|
const a = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
|
||||||
const b = aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r;
|
const b = aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r;
|
||||||
|
|
||||||
const r = s? a: b;
|
let r = s ? a: b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
function main () {
|
function main () {
|
||||||
let b = false;
|
const b = false;
|
||||||
const a = !b;
|
const a = !b;
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
circuit PedersenHash {
|
circuit PedersenHash {
|
||||||
parameters: [u32; 512]
|
parameters: [u32; 512]
|
||||||
|
|
||||||
function new(parameters: [u32; 512]) -> Self {
|
function new(const parameters: [u32; 512]) -> Self {
|
||||||
return Self { parameters: parameters };
|
return Self { parameters: parameters };
|
||||||
}
|
}
|
||||||
|
|
||||||
function hash(self, bits: [bool; 512]) -> u32 {
|
function hash(self, const bits: [bool; 512]) -> u32 {
|
||||||
let digest: u32 = 0;
|
let digest: u32 = 0;
|
||||||
for i in 0..512 {
|
for i in 0..512 {
|
||||||
const base = bits[i] ? self.parameters[i] : 0u32;
|
let base = bits[i] ? self.parameters[i] : 0u32;
|
||||||
digest += base;
|
digest += base;
|
||||||
}
|
}
|
||||||
return digest;
|
return digest;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import core.unstable.blake2s.Blake2s;
|
import core.unstable.blake2s.Blake2s;
|
||||||
|
|
||||||
function main(seed: [u8; 32], message: [u8; 32], expected: [u8; 32]) {
|
function main(seed: [u8; 32], message: [u8; 32], expected: [u8; 32]) {
|
||||||
const actual = Blake2s::hash(seed, message);
|
let actual = Blake2s::hash(seed, message);
|
||||||
|
|
||||||
console.assert(expected == actual);
|
console.assert(expected == actual);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: field, b: field, c: field) {
|
function main(s: bool, a: field, b: field, c: field) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
function main(a: group) {
|
function main(a: group) {
|
||||||
const b = a;
|
let b = a;
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: group, b: group, c: group) {
|
function main(s: bool, a: group, b: group, c: group) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i128, b: i128, c: i128) {
|
function main(s: bool, a: i128, b: i128, c: i128) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i16, b: i16, c: i16) {
|
function main(s: bool, a: i16, b: i16, c: i16) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i32, b: i32, c: i32) {
|
function main(s: bool, a: i32, b: i32, c: i32) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i64, b: i64, c: i64) {
|
function main(s: bool, a: i64, b: i64, c: i64) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i8, b: i8, c: i8) {
|
function main(s: bool, a: i8, b: i8, c: i8) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u128, b: u128, c: u128) {
|
function main(s: bool, a: u128, b: u128, c: u128) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u16, b: u16, c: u16) {
|
function main(s: bool, a: u16, b: u16, c: u16) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u32, b: u32, c: u32) {
|
function main(s: bool, a: u32, b: u32, c: u32) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u64, b: u64, c: u64) {
|
function main(s: bool, a: u64, b: u64, c: u64) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u8, b: u8, c: u8) {
|
function main(s: bool, a: u8, b: u8, c: u8) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main () {
|
function main () {
|
||||||
let x = 2u8;
|
let x = 2u8;
|
||||||
let y = x;
|
let y = x;
|
||||||
const z = y / 2u8;
|
let z = y / 2u8;
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// Swap two elements of an array.
|
// Swap two elements of an array.
|
||||||
function swap(a: [u32; 2], const i: u32, const j: u32) -> [u32; 2] {
|
function swap(a: [u32; 2], const i: u32, const j: u32) -> [u32; 2] {
|
||||||
const t = a[i];
|
let t = a[i];
|
||||||
a[i] = a[j];
|
a[i] = a[j];
|
||||||
a[j] = t;
|
a[j] = t;
|
||||||
return a;
|
return a;
|
||||||
@ -11,7 +11,7 @@ function main() {
|
|||||||
const expected: [u32; 2] = [1, 0];
|
const expected: [u32; 2] = [1, 0];
|
||||||
|
|
||||||
// Do swap.
|
// Do swap.
|
||||||
const actual = swap(arr, 0, 1);
|
let actual = swap(arr, 0, 1);
|
||||||
|
|
||||||
// Check result.
|
// Check result.
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
|
@ -7,7 +7,7 @@ function main(a: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const r: u32 = a ? 6 : 0;
|
let r: u32 = a ? 6 : 0;
|
||||||
|
|
||||||
console.assert(r == b);
|
console.assert(r == b);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
function main(a: bool, b: bool) {
|
function main(a: bool, b: bool) {
|
||||||
const c = a ? true : false;
|
let c = a ? true : false;
|
||||||
|
|
||||||
const d = c == b;
|
let d = c == b;
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ function main(s: bool, c: address) {
|
|||||||
const a = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
|
const a = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
|
||||||
const b = aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r;
|
const b = aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r;
|
||||||
|
|
||||||
const r = s? a: b;
|
let r = s ? a: b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
function main () {
|
function main () {
|
||||||
let b = false;
|
const b = false;
|
||||||
const a = !b;
|
const a = !b;
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
circuit PedersenHash {
|
circuit PedersenHash {
|
||||||
parameters: [u32; 512]
|
parameters: [u32; 512]
|
||||||
|
|
||||||
function new(parameters: [u32; 512]) -> Self {
|
function new(const parameters: [u32; 512]) -> Self {
|
||||||
return Self { parameters: parameters };
|
return Self { parameters: parameters };
|
||||||
}
|
}
|
||||||
|
|
||||||
function hash(self, bits: [bool; 512]) -> u32 {
|
function hash(self, const bits: [bool; 512]) -> u32 {
|
||||||
let digest: u32 = 0;
|
let digest: u32 = 0;
|
||||||
for i in 0..512 {
|
for i in 0..512 {
|
||||||
const base = bits[i] ? self.parameters[i] : 0u32;
|
let base = bits[i] ? self.parameters[i] : 0u32;
|
||||||
digest += base;
|
digest += base;
|
||||||
}
|
}
|
||||||
return digest;
|
return digest;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import core.unstable.blake2s.Blake2s;
|
import core.unstable.blake2s.Blake2s;
|
||||||
|
|
||||||
function main(seed: [u8; 32], message: [u8; 32], expected: [u8; 32]) {
|
function main(seed: [u8; 32], message: [u8; 32], expected: [u8; 32]) {
|
||||||
const actual = Blake2s::hash(seed, message);
|
let actual = Blake2s::hash(seed, message);
|
||||||
|
|
||||||
console.assert(expected == actual);
|
console.assert(expected == actual);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i128, b: i128, c: i128) {
|
function main(s: bool, a: i128, b: i128, c: i128) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i16, b: i16, c: i16) {
|
function main(s: bool, a: i16, b: i16, c: i16) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i32, b: i32, c: i32) {
|
function main(s: bool, a: i32, b: i32, c: i32) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i64, b: i64, c: i64) {
|
function main(s: bool, a: i64, b: i64, c: i64) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: i8, b: i8, c: i8) {
|
function main(s: bool, a: i8, b: i8, c: i8) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u128, b: u128, c: u128) {
|
function main(s: bool, a: u128, b: u128, c: u128) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u16, b: u16, c: u16) {
|
function main(s: bool, a: u16, b: u16, c: u16) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u32, b: u32, c: u32) {
|
function main(s: bool, a: u32, b: u32, c: u32) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u64, b: u64, c: u64) {
|
function main(s: bool, a: u64, b: u64, c: u64) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main(s: bool, a: u8, b: u8, c: u8) {
|
function main(s: bool, a: u8, b: u8, c: u8) {
|
||||||
const r = s ? a : b;
|
let r = s ? a : b;
|
||||||
|
|
||||||
console.assert(r == c);
|
console.assert(r == c);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
function main () {
|
function main () {
|
||||||
let x = 2u8;
|
let x = 2u8;
|
||||||
let y = x;
|
let y = x;
|
||||||
const z = y / 2u8;
|
let z = y / 2u8;
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// Swap two elements of an array.
|
// Swap two elements of an array.
|
||||||
function swap(a: [u32; 2], const i: u32, const j: u32) -> [u32; 2] {
|
function swap(a: [u32; 2], const i: u32, const j: u32) -> [u32; 2] {
|
||||||
const t = a[i];
|
let t = a[i];
|
||||||
a[i] = a[j];
|
a[i] = a[j];
|
||||||
a[j] = t;
|
a[j] = t;
|
||||||
return a;
|
return a;
|
||||||
@ -11,7 +11,7 @@ function main() {
|
|||||||
const expected: [u32; 2] = [1, 0];
|
const expected: [u32; 2] = [1, 0];
|
||||||
|
|
||||||
// Do swap.
|
// Do swap.
|
||||||
const actual = swap(arr, 0, 1);
|
let actual = swap(arr, 0, 1);
|
||||||
|
|
||||||
// Check result.
|
// Check result.
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
|
@ -7,7 +7,7 @@ function main(a: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const r: u32 = a ? 6 : 0;
|
let r: u32 = a ? 6 : 0;
|
||||||
|
|
||||||
console.assert(r == b);
|
console.assert(r == b);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,14 @@ fn test_ternary_basic() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ternary_non_const_conditional_fail() {
|
||||||
|
let program_string = include_str!("ternary_non_const_conditional_fail.leo");
|
||||||
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
|
expect_asg_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
// Iteration for i {start}..{stop} { statements }
|
// Iteration for i {start}..{stop} { statements }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
function main(a: bool, b: bool) {
|
function main(a: bool, b: bool) {
|
||||||
const c = a ? true : false;
|
let c = a ? true : false;
|
||||||
|
|
||||||
const d = c == b;
|
let d = c == b;
|
||||||
}
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
function main() {
|
||||||
|
let x = 3u8;
|
||||||
|
const y = x > 2u8? 1u8 : 2u8;
|
||||||
|
}
|
@ -21,7 +21,7 @@ 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.
|
||||||
@ -61,7 +61,7 @@ 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.
|
||||||
|
|
||||||
@ -76,31 +76,48 @@ there is no notion of Unicode encoding (e.g. UTF-8) that applies here.
|
|||||||
We add a new kind of literals for characters,
|
We add a new kind of literals for characters,
|
||||||
consisting of single characters or escapes,
|
consisting of single characters or escapes,
|
||||||
surrounded by single quotes.
|
surrounded by single quotes.
|
||||||
Any single Unicode character except single quote is allowed,
|
Any single Unicode character except a single quote is allowed,
|
||||||
e.g. `'a'`, `'*'`, and `'"'`.
|
e.g. `'a'`, `'*'`, and `'"'`.
|
||||||
Single quotes must be escaped with 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'`.]_
|
namely _[TODO: Decide which other escapes we want to allow, e.g. `'\n'`.]_
|
||||||
|
* `\n`
|
||||||
|
* `\r`
|
||||||
|
* `\t`
|
||||||
|
* `\0`
|
||||||
|
* `\'`
|
||||||
|
* `\"`
|
||||||
|
|
||||||
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 or more 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 10FFFFh.
|
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 codepoints are disallowed.
|
||||||
_[TODO: Do we want a different notation for Unicode escapes?
|
_[TODO: Do we want a different notation for Unicode escapes?
|
||||||
Note that the `{` `}` delimiters are motivated by the fact that
|
Note that the `{` `}` delimiters are motivated by the fact that
|
||||||
there may be a varying number of hex digits in this notation.]_
|
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
|
_[TODO: Which (initial) built-in or library operations
|
||||||
do we want to provide for `char` values?]_
|
do we want to provide for `char` values?]_
|
||||||
|
- [ ] 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.
|
||||||
|
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
|
|
||||||
In this initial design proposal, we do not introduce any new type for strings.
|
In this initial design proposal, we do not introduce any new type for strings.
|
||||||
Instead, we rely on the fact that Leo already has arrays,
|
Instead, we rely on the fact that Leo already has arrays
|
||||||
and that arrays of characters can be regarded as strings.
|
and that arrays of characters can be regarded as strings.
|
||||||
Existing array operations, such as element and range access,
|
Existing array operations, such as element and range access,
|
||||||
apply to these strings without the need of language extensions.
|
apply to these strings without the need of language extensions.
|
||||||
@ -112,7 +129,7 @@ surrounded by double quotes;
|
|||||||
this is just syntactic sugar.
|
this is just syntactic sugar.
|
||||||
Any single Unicode character except double quote is allowed,
|
Any single Unicode character except double quote is allowed,
|
||||||
e.g. `""`, `"Aleo"`, `"it's"`, and `"x + y"`.
|
e.g. `""`, `"Aleo"`, `"it's"`, and `"x + y"`.
|
||||||
Double quotes must be escaped with backslash, e.g. `"say \"hi\""`;
|
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).
|
||||||
@ -120,9 +137,9 @@ _[TODO: There is a difference in the treatment of single and double quotes:
|
|||||||
the former are allowed in string literals but not character literals,
|
the former are allowed in string literals but not character literals,
|
||||||
while the latter are allowed in character literals but not string literals;
|
while the latter are allowed in character literals but not string literals;
|
||||||
this asymmetry is also present in Java.
|
this asymmetry is also present in Java.
|
||||||
However, for simplicity we may want to symmetrically disallow
|
However, for simplicity, we may want to symmetrically disallow
|
||||||
both single and double quotes in both character and string literals.]_
|
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]`,
|
||||||
where `N` is the length of the string measured in characters,
|
where `N` is the length of the string measured in characters,
|
||||||
@ -131,7 +148,7 @@ Note that there is no notion of Unicode encoding (e.g. UTF-8)
|
|||||||
that applies to string literals.
|
that applies to string literals.
|
||||||
|
|
||||||
The rationale for not introducing a new type for strings initially,
|
The rationale for not introducing a new type for strings initially,
|
||||||
and instead piggyback on the existing array types and operations,
|
and instead, piggyback on the existing array types and operations,
|
||||||
is twofold.
|
is twofold.
|
||||||
First, it is an economical design
|
First, it is an economical design
|
||||||
that lets us reuse the existing array machinery,
|
that lets us reuse the existing array machinery,
|
||||||
@ -141,21 +158,27 @@ and at the R1CS compilation level
|
|||||||
Second, it leaves the door open to providing,
|
Second, it leaves the door open to providing,
|
||||||
in a future design iteration,
|
in a future design iteration,
|
||||||
a richer type for strings,
|
a richer type for strings,
|
||||||
as disccused in the section about future extensions below.
|
as discussed in the section about future extensions below.
|
||||||
|
|
||||||
_[TODO: Which (initial) built-in or library operations
|
_[TODO: Which (initial) built-in or library operations
|
||||||
do we want to provide for `[char; N]` values that are not already
|
do we want to provide for `[char; N]` values that are not already
|
||||||
available with the existing array operations?]_
|
available with the existing array operations?]_
|
||||||
* `u8` to `[char; 2]` hexstring, .., `u128` to `[char; 32]` hexstring
|
- [ ] `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)
|
- [ ] 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)
|
||||||
* _[TODO: more?]_
|
- [ ] len - Returns the length of the `string`.
|
||||||
|
- [ ] is_empty - Returns `true` if the `string` is empty.
|
||||||
|
- [ ] 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
|
## Input and Output of Literal Characters and Strings
|
||||||
|
|
||||||
Since UTF-8 is a standard encoding, it would make sense for
|
Since UTF-8 is a standard encoding, it would make sense for
|
||||||
the literal characters and strings in the `.in` file
|
the literal characters and strings in the `.in` file
|
||||||
to be automatically converted to UTF-32 by the Leo compiler.
|
to be automatically converted to UTF-32 by the Leo compiler.
|
||||||
However, the size of a string can be confusing, since multiple
|
However, the size of a string can be confusing since multiple
|
||||||
Unicode code points can be composed into a single glyph which
|
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]`
|
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
|
[if that is the syntax we decide on] is passed a literal string
|
||||||
@ -169,16 +192,16 @@ usable exclusively as first arguments of console print calls.
|
|||||||
This proposal eliminates this very specific notion,
|
This proposal eliminates this very specific notion,
|
||||||
which is subsumed by the string literals described above.
|
which is subsumed by the string literals described above.
|
||||||
In other words, a console print call
|
In other words, a console print call
|
||||||
will simply take a string literal as first argument,
|
will take a string literal as the first argument,
|
||||||
which will be interpreted as a format string
|
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.
|
||||||
|
|
||||||
## Compilation to R1CS
|
## Compilation to R1CS
|
||||||
|
|
||||||
So far the discussion has been independent from R1CS
|
So far, the discussion has been independent from R1CS
|
||||||
(except for a brief reference when discussing the rationale behind the design).
|
(except for a brief reference when discussing the rationale behind the design).
|
||||||
This is intentional, because the syntax and semantics of Leo
|
This is intentional because the syntax and semantics of Leo
|
||||||
should be understandable independently from the compilation of Leo to R1CS.
|
should be understandable independently from the compilation of Leo to R1CS.
|
||||||
However, compilation to R1CS is a critical consideration
|
However, compilation to R1CS is a critical consideration
|
||||||
that affects the design of Leo.
|
that affects the design of Leo.
|
||||||
@ -206,10 +229,10 @@ suitable array inline construction expressions.
|
|||||||
## Future Extensions
|
## Future Extensions
|
||||||
|
|
||||||
As alluded to in the section about design above,
|
As alluded to in the section about design above,
|
||||||
for now we are avoiding the introduction of a string type,
|
for now, we are avoiding the introduction of a string type,
|
||||||
isomorphic to but separate from character arrays,
|
isomorphic to but separate from character arrays,
|
||||||
because we may want to introduce later a more flexible type of strings,
|
because we may want to introduce later a more flexible type of strings,
|
||||||
in particular one that supports resizing.
|
in particular, one that supports resizing.
|
||||||
This may be realized via a built-in or library circuit type
|
This may be realized via a built-in or library circuit type
|
||||||
that includes a character array and a fill index.
|
that includes a character array and a fill index.
|
||||||
This may be a special case of a built-in or library circuit type
|
This may be a special case of a built-in or library circuit type
|
||||||
@ -240,7 +263,7 @@ to/from common formats, e.g. UTF-8.
|
|||||||
# 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 10FFFFh,
|
||||||
and that signed integer types include negative integers
|
and that signed integer types include negative integers
|
||||||
@ -254,7 +277,7 @@ All in all, introducing a new type for characters
|
|||||||
is consistent with Leo's strong typing approach.
|
is consistent with Leo's strong typing approach.
|
||||||
Furthermore, for compilation to R1CS, `u32`,
|
Furthermore, for compilation to R1CS, `u32`,
|
||||||
even if restricted to the number of bits needed for Unicode code points,
|
even if restricted to the number of bits needed for Unicode code points,
|
||||||
is less efficient than the field representation described earlier,
|
is less efficient than the field representation described earlier
|
||||||
because `u32` requires a field element for each bit.
|
because `u32` requires a field element for each bit.
|
||||||
|
|
||||||
Instead of representing strings as character arrays,
|
Instead of representing strings as character arrays,
|
||||||
@ -264,9 +287,9 @@ These strings would be isomorphic to, but distinct form, character arrays.
|
|||||||
However, for compilation to R1CS, it would be necessary to
|
However, for compilation to R1CS, it would be necessary to
|
||||||
perform the same kind of known-size analysis on strings
|
perform the same kind of known-size analysis on strings
|
||||||
that is already performed on arrays,
|
that is already performed on arrays,
|
||||||
possibly necessitating to include a size as part of the type, i.e. `string(N)`,
|
possibly necessitating to include size as part of the type, i.e. `string(N)`,
|
||||||
which is obviously isomorphic to `[char; N]`.
|
which is obviously isomorphic to `[char; N]`.
|
||||||
Thus, using character arrays avoids the duplication.
|
Thus, using character arrays avoids duplication.
|
||||||
Furthermore, as noted in the section on future extensions,
|
Furthermore, as noted in the section on future extensions,
|
||||||
this leaves the door open to
|
this leaves the door open to
|
||||||
introducing a future type `string` for resizable strings.
|
introducing a future type `string` for resizable strings.
|
||||||
|
Loading…
Reference in New Issue
Block a user