Merge branch 'master' into leo-manifest-dependencies

This commit is contained in:
damirka 2021-07-22 15:13:44 +03:00
commit 6a2ebfc22e
383 changed files with 2023 additions and 6995 deletions

0
FORMAT_ABNF_GRAMMER.md Normal file
View File

View File

@ -92,7 +92,7 @@ impl<'a> MonoidalReducerStatement<'a, BoolAnd> for ReturnPathReducer {
if_true.append(if_false.unwrap_or(BoolAnd(false)))
}
fn reduce_formatted_string(&mut self, input: &FormatString, parameters: Vec<BoolAnd>) -> BoolAnd {
fn reduce_formatted_string(&mut self, input: &ConsoleArgs, parameters: Vec<BoolAnd>) -> BoolAnd {
BoolAnd(false)
}

View File

@ -109,13 +109,29 @@ pub enum CharValue {
NonScalar(u32),
}
impl From<&leo_ast::Char> for CharValue {
fn from(other: &leo_ast::Char) -> Self {
use leo_ast::Char::*;
match other {
Scalar(value) => CharValue::Scalar(*value),
NonScalar(value) => CharValue::NonScalar(*value),
}
}
}
impl Into<leo_ast::Char> for &CharValue {
fn into(self) -> leo_ast::Char {
use leo_ast::Char::*;
match self {
CharValue::Scalar(value) => Scalar(*value),
CharValue::NonScalar(value) => NonScalar(*value),
}
}
}
impl From<leo_ast::CharValue> for CharValue {
fn from(other: leo_ast::CharValue) -> Self {
use leo_ast::Char::*;
match other.character {
Scalar(value) => CharValue::Scalar(value),
NonScalar(value) => CharValue::NonScalar(value),
}
Self::from(&other.character)
}
}

View File

@ -148,24 +148,28 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
_ => None,
};
let const_right = match right.map(|x| x.const_value()) {
Some(Some(ConstValue::Int(value))) => {
let value = value.to_usize();
if let Some(value) = value {
if value > parent_size {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&right.unwrap().span().cloned().unwrap_or_default(),
));
Some(Some(ConstValue::Int(inner_value))) => {
let usize_value = inner_value.to_usize();
if let Some(inner_value) = usize_value {
if inner_value > parent_size {
let error_span = if let Some(right) = right {
right.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgConvertError::array_index_out_of_bounds(inner_value, &error_span));
} else if let Some(left) = const_left {
if left > value {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&right.unwrap().span().cloned().unwrap_or_default(),
));
if left > inner_value {
let error_span = if let Some(right) = right {
right.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgConvertError::array_index_out_of_bounds(inner_value, &error_span));
}
}
}
value
usize_value
}
None => Some(parent_size),
_ => None,
@ -188,12 +192,14 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
));
}
}
if let Some(value) = const_left {
if value + expected_len > parent_size {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&left.unwrap().span().cloned().unwrap_or_default(),
));
if let Some(left_value) = const_left {
if left_value + expected_len > parent_size {
let error_span = if let Some(left) = left {
left.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgConvertError::array_index_out_of_bounds(left_value, &error_span));
}
}
length = Some(expected_len);

View File

@ -225,7 +225,7 @@ impl<'a, T: Monoid, R: MonoidalReducerStatement<'a, T>> MonoidalDirector<'a, T,
.reduce_conditional_statement(input, condition, if_true, if_false)
}
pub fn reduce_formatted_string(&mut self, input: &FormatString<'a>) -> T {
pub fn reduce_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> T {
let parameters = input
.parameters
.iter()

View File

@ -118,7 +118,7 @@ pub trait MonoidalReducerStatement<'a, T: Monoid>: MonoidalReducerExpression<'a,
condition.append(if_true).append_option(if_false)
}
fn reduce_formatted_string(&mut self, input: &FormatString<'a>, parameters: Vec<T>) -> T {
fn reduce_formatted_string(&mut self, input: &ConsoleArgs<'a>, parameters: Vec<T>) -> T {
T::default().append_all(parameters.into_iter())
}

View File

@ -243,7 +243,7 @@ impl<'a, R: ReconstructingReducerStatement<'a>> ReconstructingDirector<'a, R> {
.reduce_conditional_statement(input, condition, if_true, if_false)
}
pub fn reduce_formatted_string(&mut self, input: FormatString<'a>) -> FormatString<'a> {
pub fn reduce_formatted_string(&mut self, input: ConsoleArgs<'a>) -> ConsoleArgs<'a> {
let parameters = input
.parameters
.iter()

View File

@ -274,12 +274,12 @@ pub trait ReconstructingReducerStatement<'a>: ReconstructingReducerExpression<'a
fn reduce_formatted_string(
&mut self,
input: FormatString<'a>,
input: ConsoleArgs<'a>,
parameters: Vec<&'a Expression<'a>>,
) -> FormatString<'a> {
FormatString {
) -> ConsoleArgs<'a> {
ConsoleArgs {
span: input.span,
parts: input.parts,
string: input.string,
parameters: parameters.into_iter().map(Cell::new).collect(),
}
}
@ -293,7 +293,7 @@ pub trait ReconstructingReducerStatement<'a>: ReconstructingReducerExpression<'a
})
}
fn reduce_console_log(&mut self, input: ConsoleStatement<'a>, argument: FormatString<'a>) -> Statement<'a> {
fn reduce_console_log(&mut self, input: ConsoleStatement<'a>, argument: ConsoleArgs<'a>) -> Statement<'a> {
assert!(!matches!(input.function, ConsoleFunction::Assert(_)));
Statement::Console(ConsoleStatement {
parent: input.parent,

View File

@ -120,7 +120,7 @@ pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
Default::default()
}
fn visit_formatted_string(&mut self, input: &FormatString<'a>) -> VisitResult {
fn visit_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> VisitResult {
Default::default()
}

View File

@ -319,7 +319,7 @@ impl<'a, R: StatementVisitor<'a>> VisitorDirector<'a, R> {
}
}
pub fn visit_formatted_string(&mut self, input: &FormatString<'a>) -> ConcreteVisitResult {
pub fn visit_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> ConcreteVisitResult {
match self.visitor.visit_formatted_string(input) {
VisitResult::VisitChildren => {
for parameter in input.parameters.iter() {

View File

@ -14,15 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
use leo_ast::{ConsoleFunction as AstConsoleFunction, FormatStringPart};
use crate::{AsgConvertError, CharValue, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
use leo_ast::ConsoleFunction as AstConsoleFunction;
use std::cell::Cell;
// TODO (protryon): Refactor to not require/depend on span
#[derive(Clone)]
pub struct FormatString<'a> {
pub parts: Vec<FormatStringPart>,
pub struct ConsoleArgs<'a> {
pub string: Vec<CharValue>,
pub parameters: Vec<Cell<&'a Expression<'a>>>,
pub span: Span,
}
@ -30,9 +30,9 @@ pub struct FormatString<'a> {
#[derive(Clone)]
pub enum ConsoleFunction<'a> {
Assert(Cell<&'a Expression<'a>>),
Debug(FormatString<'a>),
Error(FormatString<'a>),
Log(FormatString<'a>),
Debug(ConsoleArgs<'a>),
Error(ConsoleArgs<'a>),
Log(ConsoleArgs<'a>),
}
#[derive(Clone)]
@ -48,41 +48,28 @@ impl<'a> Node for ConsoleStatement<'a> {
}
}
impl<'a> FromAst<'a, leo_ast::FormatString> for FormatString<'a> {
impl<'a> FromAst<'a, leo_ast::ConsoleArgs> for ConsoleArgs<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::FormatString,
value: &leo_ast::ConsoleArgs,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self, AsgConvertError> {
let expected_param_len = value
.parts
.iter()
.filter(|x| matches!(x, FormatStringPart::Container))
.count();
if value.parameters.len() != expected_param_len {
// + 1 for formatting string as to not confuse user
return Err(AsgConvertError::unexpected_call_argument_count(
expected_param_len + 1,
value.parameters.len() + 1,
&value.span,
));
}
let mut parameters = vec![];
for parameter in value.parameters.iter() {
parameters.push(Cell::new(<&Expression<'a>>::from_ast(scope, parameter, None)?));
}
Ok(FormatString {
parts: value.parts.clone(),
Ok(ConsoleArgs {
string: value.string.iter().map(CharValue::from).collect::<Vec<_>>(),
parameters,
span: value.span.clone(),
})
}
}
impl<'a> Into<leo_ast::FormatString> for &FormatString<'a> {
fn into(self) -> leo_ast::FormatString {
leo_ast::FormatString {
parts: self.parts.clone(),
impl<'a> Into<leo_ast::ConsoleArgs> for &ConsoleArgs<'a> {
fn into(self) -> leo_ast::ConsoleArgs {
leo_ast::ConsoleArgs {
string: self.string.iter().map(|c| c.into()).collect::<Vec<_>>(),
parameters: self.parameters.iter().map(|e| e.get().into()).collect(),
span: self.span.clone(),
}
@ -102,15 +89,9 @@ impl<'a> FromAst<'a, leo_ast::ConsoleStatement> for ConsoleStatement<'a> {
AstConsoleFunction::Assert(expression) => ConsoleFunction::Assert(Cell::new(
<&Expression<'a>>::from_ast(scope, expression, Some(Type::Boolean.into()))?,
)),
AstConsoleFunction::Debug(formatted_string) => {
ConsoleFunction::Debug(FormatString::from_ast(scope, formatted_string, None)?)
}
AstConsoleFunction::Error(formatted_string) => {
ConsoleFunction::Error(FormatString::from_ast(scope, formatted_string, None)?)
}
AstConsoleFunction::Log(formatted_string) => {
ConsoleFunction::Log(FormatString::from_ast(scope, formatted_string, None)?)
}
AstConsoleFunction::Debug(args) => ConsoleFunction::Debug(ConsoleArgs::from_ast(scope, args, None)?),
AstConsoleFunction::Error(args) => ConsoleFunction::Error(ConsoleArgs::from_ast(scope, args, None)?),
AstConsoleFunction::Log(args) => ConsoleFunction::Log(ConsoleArgs::from_ast(scope, args, None)?),
},
})
}
@ -122,9 +103,9 @@ impl<'a> Into<leo_ast::ConsoleStatement> for &ConsoleStatement<'a> {
leo_ast::ConsoleStatement {
function: match &self.function {
Assert(e) => AstConsoleFunction::Assert(e.get().into()),
Debug(formatted_string) => AstConsoleFunction::Debug(formatted_string.into()),
Error(formatted_string) => AstConsoleFunction::Error(formatted_string.into()),
Log(formatted_string) => AstConsoleFunction::Log(formatted_string.into()),
Debug(args) => AstConsoleFunction::Debug(args.into()),
Error(args) => AstConsoleFunction::Error(args.into()),
Log(args) => AstConsoleFunction::Log(args.into()),
},
span: self.span.clone().unwrap_or_default(),
}

View File

@ -1,3 +0,0 @@
function main() {
console.log("{}");
}

View File

@ -1,3 +0,0 @@
function main() {
console.log("", 1u32);
}

View File

@ -27,15 +27,3 @@ fn test_log_parameter_fail_unknown() {
let program_string = include_str!("log_parameter_fail_unknown.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_log_parameter_fail_empty() {
let program_string = include_str!("log_parameter_fail_empty.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_log_parameter_fail_none() {
let program_string = include_str!("log_parameter_fail_empty.leo");
load_asg(program_string).err().unwrap();
}

View File

@ -1,5 +1,343 @@
# leo-ast
[![Crates.io](https://img.shields.io/crates/v/leo-ast.svg?color=neon)](https://crates.io/crates/leo-ast)
[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](../AUTHORS)
[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md)
This directory contains the code for the AST of a Leo Program.
## Node Types
There are several types of nodes in the AST that then have further breakdowns.
All nodes store a Span, which is useful for tracking the lines and
columns of where the node was taken from in the Leo Program.
### [Program/File](./src/program.rs)
The top level nodes in a Leo Program.
#### [Imports](./src/imports/import.rs)
Represents an import statement in a Leo Program.
A list of these are stored on the Program.
It stores the path to an import and what is being imported.
**NOTE**: The import does not contain the source code of the imported Leo Program.
#### [Circuits](./src/circuits/circuit.rs)
A circuit node represents a defined Circuit in a Leo Program.
A order preserving map of these are stored on the Program.
Contains the Circuit's name, as well as it's members.
The members are a function, or a variable.
For both of them the Circuit preserves their names.
#### [Decorators](./src/annotation.rs)
An annotation node is a decorator that can be applied to a function.
Stored on the function themselves despite being a top-level node.
The node stores the name of the annotation, as well as any args passed to it.
#### [Functions](./src/functions/function.rs)
A function node represents a defined function in a Leo Program.
A order preserving map of these are stored on the Program.
A function node stores the following information:
- The annotations applied to the function.
- An identifier the name of the function.
- The inputs to the function, both their names and types.
- The output of the function as a type if it exists.
- The function body stored as a block statement.
#### [Global Consts](./src/program.rs)
A global const is a bit special and has no special node for itself, but rather is a definition statement.
A order preserving map of these are stored on the Program.
### [Types](./src/types/type_.rs)
The different types in a Leo Program.
Types themselves are not a node, but rather just information to be stored on a node.
#### Address
The address type follows the [BIP_0173](https://en.bitcoin.it/wiki/BIP_0173) format starting with `aleo1`.
#### Boolean
The boolean type consists of two values **true** and **false**.
#### Char
The char type resents a character from the inclusive range [0, 10FFFF].
#### Field
The field type an unsigned number up to the modulus length of the field.
#### Group
The group type a set of affine points on the elliptic curve passed.
#### [IntegerType](./src/types/integer_type.rs)
The integer type represents a range of integer types.
##### U8
A integer in the inclusive range [0, 255].
##### U16
A integer in the inclusive range [0, 65535].
##### U32
A integer in the inclusive range [0, 4294967295].
##### U64
A integer in the inclusive range [0, 18446744073709551615].
##### U128
A integer in the inclusive range [0, 340282366920938463463374607431768211455].
##### I8
A integer in the inclusive range [-128, 127].
##### I16
A integer in the inclusive range [-32768, 32767].
##### I32
A integer in the inclusive range [-2147483648, 2147483647].
##### I64
A integer in the inclusive range [-9223372036854775808, 9223372036854775807].
##### I128
A integer in the inclusive range [-170141183460469231731687303715884105728, 170141183460469231731687303715884105727].
#### Array
The array type contains another type, then the number of elements of that type greater than 0.
#### Tuple
The tuple type contains n types, where n is greater than or equal to 0.
#### Circuit
The circuit type, every circuit represents a different type.
#### SelfType
The self type represented by `Self` and only usable inside a circuit.
### [Statements](./src/statements/statement.rs)
The statement level nodes in a Leo Program.
#### [Assignment Statements](./src/statements/assign/)
An assignment statement node stores the following:
- The operation.
- **=**
- **+=**
- **-=**
- **=**
- **/=**
- **=**
- **&&=**
- **||=**
- The assignee which is a variable that has context of any access expressions on it.
- The value which is an expression.
#### [Block Statements](./src/statements/block.rs)
A block statement node stores the following:
- The list of statements inside the block.
#### [Conditional Statements](./src/statements/conditional.rs)
A conditional statement node stores the following:
- The condition which is an expression.
- The block statement.
- The next block of the conditional if it exists.
#### [Console Statements](./src/statements/)
A console statement node stores the following:
- The console function being called which stores the type of console function it is and its arguments.
#### [Definition Statements](./src/statements/definition/mod.rs)
A definition statement node stores the following:
- The declaration type:
- `let` for mutable definitions.
- `const` for cosntant definitions.
- The names of the varaibles defined.
- The optional type.
- The values to be assigned to the varaibles.
#### [Expression Statements](./src/statements/expression.rs)
An expression statement node stores the following:
- The expression.
#### [Iteration Statements](./src/statements/iteration.rs)
A iteration statement node stores the following:
- The loop iterator variable name.
- The expression to define the starting loop value.
- The expression to define the stoping loop value.
- The block to run for the loop.
#### [Return Statements](./src/statements/return_statement.rs)
A return statement node stores the following:
- The expression that is being returned.
### Expressions
The expression nodes in a Leo Program.
#### [ArrayAccess Expressions](./src/expression/array_acces.rs)
An array access expression node stores the following:
- The array expression.
- The index represented by an expression.
#### [ArrayInit Expressions](./src/expression/array_init.rs)
An array init expression node stores the following:
- The element expression to fill the array with.
- The dimensions of the array to build.
#### [ArrayInline Expressions](./src/expression/array_inline.rs)
An array inline expression node stores the following:
- The elments of an array which is either an spread or an expression.
#### [ArrayRangeAccess Expressions](./src/expression/array_range_access.rs)
An array range access expression node stores the following:
- The array expression.
- The optional left side of the range of the array bounds to access.
- The optional right side of the range of the array bounds to access.
#### [Binary Expressions](./src/expression/binary.rs)
A binary expression node stores the following:
- The left side of the expression.
- The right side of the expression.
- The binary operation of the expression:
- **+**
- **-**
- **\***
- **/**
- **\*\***
- **||**
- **&&**
- **==**
- **!=**
- **>=**
- **>**
- **<=**
- **<**
#### [Call Expressions](./src/expression/call.rs)
A call expression node stores the following:
- The function expression being called.
- The aruments a list of expressions.
#### [CircuitInit Expressions](./src/expression/circuit_init.rs)
A circuit init expression node stores the following:
- The name of the circuit expression being initialized.
- The aruments a list of expressions.
#### [CircuitMemberAccess Expressions](./src/expression/circuit_member_access.rs)
A circuit member access expression node stores the following:
- The circut expression being accessed.
- The name of the expression being accessed from the circuit.
#### [CircuitStaticFunctionAccess Expressions](./src/expression/circuit_static_function_access.rs)
A circuit static function access expression node stores the following:
- The circut expression being accessed.
- The name of the expression being statically accessed from the circuit.
#### [Identifier Expressions](./src/common/identifier.rs)
An identifer expression node stores the following:
- An identifier stores the string name.
#### [Ternary Expressions](./src/expression/ternary.rs)
A ternary expression node stores the following:
- The condition of the ternary stored as an expression.
- The expression returned if the condition is true.
- The expression returned if the condition is false.
#### [TupleAccess Expressions](./src/expression/tuple_access.rs)
A tuple access expression node stores the following:
- The tuple expression being accessed.
- The index a positive number greater than or equal to 0.
#### [TupleInit Expressions](./src/expression/tuple_init.rs)
A tuple init expression node stores the following:
- The element expressions to fill the tuple with.
#### [Unary Expressions](./src/expression/unary.rs)
An unary expression node stores the following:
- The inner expression.
- The unary operator:
- **!**
- **-**
#### [Value Expressions](./src/expression/value.rs)
A value expression node stores one of the following:
- Address and its value and span.
- Boolean and its value and span.
- Char and its value and span.
- Field and its value and span.
- Group and its value and span.
- Implicit and its value and span.
- Integer and its value and span.
- String and its value and span.

View File

@ -35,6 +35,13 @@ impl ReducerError {
ReducerError::Error(FormattedError::new_from_span(message, span))
}
pub fn empty_string(span: &Span) -> Self {
let message =
"Cannot constrcut an empty string: it has the type of [char; 0] which is not possible.".to_string();
Self::new_from_span(message, span)
}
pub fn impossible_console_assert_call(span: &Span) -> Self {
let message = "Console::Assert cannot be matched here, its handled in another case.".to_string();

View File

@ -118,6 +118,11 @@ impl Ast {
let ast: Program = serde_json::from_str(json)?;
Ok(Self { ast })
}
pub fn from_json_file(path: std::path::PathBuf) -> Result<Self, AstError> {
let data = std::fs::read_to_string(path)?;
Self::from_json_string(&data)
}
}
impl AsRef<Program> for Ast {

View File

@ -391,23 +391,23 @@ impl Canonicalizer {
ConsoleFunction::Assert(expression) => {
ConsoleFunction::Assert(self.canonicalize_expression(expression))
}
ConsoleFunction::Debug(format) | ConsoleFunction::Error(format) | ConsoleFunction::Log(format) => {
let parameters = format
ConsoleFunction::Debug(args) | ConsoleFunction::Error(args) | ConsoleFunction::Log(args) => {
let parameters = args
.parameters
.iter()
.map(|parameter| self.canonicalize_expression(parameter))
.collect();
let formatted = FormatString {
parts: format.parts.clone(),
let console_args = ConsoleArgs {
string: args.string.clone(),
parameters,
span: format.span.clone(),
span: args.span.clone(),
};
match &console_function_call.function {
ConsoleFunction::Debug(_) => ConsoleFunction::Debug(formatted),
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
ConsoleFunction::Debug(_) => ConsoleFunction::Debug(console_args),
ConsoleFunction::Error(_) => ConsoleFunction::Error(console_args),
ConsoleFunction::Log(_) => ConsoleFunction::Log(console_args),
_ => unimplemented!(), // impossible
}
}
@ -493,6 +493,10 @@ impl ReconstructingReducer for Canonicalizer {
}
fn reduce_string(&mut self, string: &[Char], span: &Span) -> Result<Expression, ReducerError> {
if string.is_empty() {
return Err(ReducerError::empty_string(span));
}
let mut elements = Vec::new();
let mut col_adder = 0;
for (index, character) in string.iter().enumerate() {

View File

@ -390,23 +390,23 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
) -> Result<ConsoleStatement, ReducerError> {
let function = match &console_function_call.function {
ConsoleFunction::Assert(expression) => ConsoleFunction::Assert(self.reduce_expression(expression)?),
ConsoleFunction::Debug(format) | ConsoleFunction::Error(format) | ConsoleFunction::Log(format) => {
ConsoleFunction::Debug(args) | ConsoleFunction::Error(args) | ConsoleFunction::Log(args) => {
let mut parameters = vec![];
for parameter in format.parameters.iter() {
for parameter in args.parameters.iter() {
parameters.push(self.reduce_expression(parameter)?);
}
let formatted = FormatString {
parts: format.parts.clone(),
let formatted = ConsoleArgs {
string: args.string.clone(),
parameters,
span: format.span.clone(),
span: args.span.clone(),
};
match &console_function_call.function {
ConsoleFunction::Debug(_) => ConsoleFunction::Debug(formatted),
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
_ => return Err(ReducerError::impossible_console_assert_call(&format.span)),
_ => return Err(ReducerError::impossible_console_assert_call(&args.span)),
}
}
};

View File

@ -14,23 +14,34 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span};
use crate::{Char, Expression, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct FormattedContainer {
pub struct ConsoleArgs {
pub string: Vec<Char>,
pub parameters: Vec<Expression>,
pub span: Span,
}
impl fmt::Display for FormattedContainer {
impl fmt::Display for ConsoleArgs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{}}")
write!(
f,
"\"{}\", {}",
self.string.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(""),
self.parameters
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(",")
)
}
}
impl Node for FormattedContainer {
impl Node for ConsoleArgs {
fn span(&self) -> &Span {
&self.span
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, FormatString, Node, Span};
use crate::{ConsoleArgs, Expression, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -22,9 +22,9 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum ConsoleFunction {
Assert(Expression),
Debug(FormatString),
Error(FormatString),
Log(FormatString),
Debug(ConsoleArgs),
Error(ConsoleArgs),
Log(ConsoleArgs),
}
impl fmt::Display for ConsoleFunction {

View File

@ -1,103 +0,0 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Char, Expression, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
use tendril::StrTendril;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum FormatStringPart {
Const(#[serde(with = "crate::common::tendril_json")] StrTendril),
Container,
}
impl FormatStringPart {
pub fn from_string(string: Vec<Char>) -> Vec<Self> {
let mut parts = Vec::new();
let mut in_container = false;
let mut substring = String::new();
for (_, character) in string.iter().enumerate() {
match character {
Char::Scalar(scalar) => match scalar {
'{' if !in_container => {
parts.push(FormatStringPart::Const(substring.clone().into()));
substring.clear();
in_container = true;
}
'}' if in_container => {
in_container = false;
parts.push(FormatStringPart::Container);
}
_ if in_container => {
in_container = false;
}
_ => substring.push(*scalar),
},
Char::NonScalar(non_scalar) => {
substring.push_str(format!("\\u{{{:x}}}", non_scalar).as_str());
in_container = false;
}
}
}
if !substring.is_empty() {
parts.push(FormatStringPart::Const(substring.into()));
}
parts
}
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct FormatString {
pub parts: Vec<FormatStringPart>,
pub parameters: Vec<Expression>,
pub span: Span,
}
impl fmt::Display for FormatString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"\"{}\", {}",
self.parts
.iter()
.map(|x| match x {
FormatStringPart::Const(x) => x.to_string(),
FormatStringPart::Container => "{}".to_string(),
})
.collect::<Vec<_>>()
.join(""),
self.parameters
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(",")
)
}
}
impl Node for FormatString {
fn span(&self) -> &Span {
&self.span
}
fn set_span(&mut self, span: Span) {
self.span = span;
}
}

View File

@ -17,11 +17,8 @@
pub mod console_function;
pub use console_function::*;
pub mod console_args;
pub use console_args::*;
pub mod console_statement;
pub use console_statement::*;
pub mod formatted_container;
pub use formatted_container::*;
pub mod formatted_string;
pub use formatted_string::*;

View File

@ -18,11 +18,11 @@
use crate::{
constraints::{generate_constraints, generate_test_constraints},
errors::CompilerError,
AstSnapshotOptions,
CompilerOptions,
GroupType,
Output,
OutputFile,
TheoremOptions,
TypeInferencePhase,
};
pub use leo_asg::{new_context, AsgContext as Context, AsgContext};
@ -69,8 +69,8 @@ pub struct Compiler<'a, F: PrimeField, G: GroupType<F>> {
context: AsgContext<'a>,
asg: Option<AsgProgram<'a>>,
options: CompilerOptions,
proof_options: TheoremOptions,
imports_map: HashMap<String, String>,
ast_snapshot_options: AstSnapshotOptions,
_engine: PhantomData<F>,
_group: PhantomData<G>,
}
@ -85,8 +85,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
output_directory: PathBuf,
context: AsgContext<'a>,
options: Option<CompilerOptions>,
proof_options: Option<TheoremOptions>,
imports_map: HashMap<String, String>,
ast_snapshot_options: Option<AstSnapshotOptions>,
) -> Self {
Self {
program_name: package_name.clone(),
@ -97,8 +97,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
asg: None,
context,
options: options.unwrap_or_default(),
proof_options: proof_options.unwrap_or_default(),
imports_map,
ast_snapshot_options: ast_snapshot_options.unwrap_or_default(),
_engine: PhantomData,
_group: PhantomData,
}
@ -117,8 +117,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
output_directory: PathBuf,
context: AsgContext<'a>,
options: Option<CompilerOptions>,
proof_options: Option<TheoremOptions>,
imports_map: HashMap<String, String>,
ast_snapshot_options: Option<AstSnapshotOptions>,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(
package_name,
@ -126,8 +126,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
output_directory,
context,
options,
proof_options,
imports_map,
ast_snapshot_options,
);
compiler.parse_program()?;
@ -158,8 +158,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
state_path: &Path,
context: AsgContext<'a>,
options: Option<CompilerOptions>,
proof_options: Option<TheoremOptions>,
imports_map: HashMap<String, String>,
ast_snapshot_options: Option<AstSnapshotOptions>,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(
package_name,
@ -167,8 +167,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
output_directory,
context,
options,
proof_options,
imports_map,
ast_snapshot_options,
);
compiler.parse_input(input_string, input_path, state_string, state_path)?;
@ -249,7 +249,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
let mut ast: leo_ast::Ast = parse_ast(self.main_file_path.to_str().unwrap_or_default(), program_string)?;
if self.proof_options.initial {
if self.ast_snapshot_options.initial {
ast.to_json_file(self.output_directory.clone(), "initial_ast.json")?;
}
@ -257,7 +257,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
if self.options.canonicalization_enabled {
ast.canonicalize()?;
if self.proof_options.canonicalized {
if self.ast_snapshot_options.canonicalized {
ast.to_json_file(self.output_directory.clone(), "canonicalization_ast.json")?;
}
}
@ -275,7 +275,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
&mut ImportParser::new(self.main_file_path.clone(), self.imports_map.clone()),
)?;
if self.proof_options.type_inferenced {
if self.ast_snapshot_options.type_inferenced {
let new_ast = TypeInferencePhase::default()
.phase_ast(&self.program, &asg.clone().into_repr())
.expect("Failed to produce type inference ast.");

View File

@ -17,8 +17,7 @@
//! Evaluates a formatted string in a compiled Leo program.
use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType};
use leo_asg::FormatString;
use leo_ast::FormatStringPart;
use leo_asg::{CharValue, ConsoleArgs};
use snarkvm_fields::PrimeField;
use snarkvm_r1cs::ConstraintSystem;
@ -26,35 +25,65 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn format<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
formatted: &FormatString<'a>,
args: &ConsoleArgs<'a>,
) -> Result<String, ConsoleError> {
// Check that containers and parameters match
let container_count = formatted
.parts
.iter()
.filter(|x| matches!(x, FormatStringPart::Container))
.count();
if container_count != formatted.parameters.len() {
return Err(ConsoleError::length(
container_count,
formatted.parameters.len(),
&formatted.span,
));
}
let mut executed_containers = Vec::with_capacity(formatted.parameters.len());
for parameter in formatted.parameters.iter() {
executed_containers.push(self.enforce_expression(cs, parameter.get())?.to_string());
}
let mut out = vec![];
let mut parameters = executed_containers.iter();
for part in formatted.parts.iter() {
match part {
FormatStringPart::Const(c) => out.push(c.to_string()),
FormatStringPart::Container => out.push(parameters.next().unwrap().to_string()),
let mut out = Vec::new();
let mut in_container = false;
let mut substring = String::new();
let mut arg_index = 0;
let mut escape_right_bracket = false;
for (index, character) in args.string.iter().enumerate() {
match character {
_ if escape_right_bracket => {
escape_right_bracket = false;
continue;
}
CharValue::Scalar(scalar) => match scalar {
'{' if !in_container => {
out.push(substring.clone());
substring.clear();
in_container = true;
}
'{' if in_container => {
substring.push('{');
in_container = false;
}
'}' if in_container => {
in_container = false;
let parameter = match args.parameters.get(arg_index) {
Some(index) => index,
None => return Err(ConsoleError::length(arg_index + 1, args.parameters.len(), &args.span)),
};
out.push(self.enforce_expression(cs, parameter.get())?.to_string());
arg_index += 1;
}
'}' if !in_container => {
if let Some(CharValue::Scalar(next)) = args.string.get(index + 1) {
if *next == '}' {
substring.push('}');
escape_right_bracket = true;
} else {
return Err(ConsoleError::expected_escaped_right_brace(&args.span));
}
}
}
_ if in_container => {
return Err(ConsoleError::expected_left_or_right_brace(&args.span));
}
_ => substring.push(*scalar),
},
CharValue::NonScalar(non_scalar) => {
substring.push_str(format!("\\u{{{:x}}}", non_scalar).as_str());
in_container = false;
}
}
}
out.push(substring);
// Check that containers and parameters match
if arg_index != args.parameters.len() {
return Err(ConsoleError::length(arg_index, args.parameters.len(), &args.span));
}
Ok(out.join(""))
}

View File

@ -33,6 +33,18 @@ impl ConsoleError {
ConsoleError::Error(FormattedError::new_from_span(message, span))
}
pub fn expected_left_or_right_brace(span: &Span) -> Self {
let message = "Formatter given a {. Expected a { or } after".to_string();
Self::new_from_span(message, span)
}
pub fn expected_escaped_right_brace(span: &Span) -> Self {
let message = "Formatter given a }. Expected a container {} or }}".to_string();
Self::new_from_span(message, span)
}
pub fn length(containers: usize, parameters: usize, span: &Span) -> Self {
let message = format!(
"Formatter given {} containers and found {} parameters",

View File

@ -65,3 +65,6 @@ pub use phases::*;
pub mod option;
pub use option::*;
#[cfg(test)]
mod test;

View File

@ -38,13 +38,13 @@ impl Default for CompilerOptions {
}
#[derive(Clone)]
pub struct TheoremOptions {
pub struct AstSnapshotOptions {
pub initial: bool,
pub canonicalized: bool,
pub type_inferenced: bool,
}
impl Default for TheoremOptions {
impl Default for AstSnapshotOptions {
fn default() -> Self {
Self {
initial: false,

View File

@ -76,12 +76,12 @@ use leo_ast::{
CircuitStaticFunctionAccessExpression,
CombinerError,
ConditionalStatement as AstConditionalStatement,
ConsoleArgs as AstConsoleArgs,
ConsoleFunction as AstConsoleFunction,
ConsoleStatement as AstConsoleStatement,
DefinitionStatement as AstDefinitionStatement,
Expression as AstExpression,
ExpressionStatement as AstExpressionStatement,
FormatString,
Function as AstFunction,
GroupTuple,
GroupValue as AstGroupValue,
@ -597,25 +597,27 @@ impl<R: ReconstructingReducer, O: CombinerOptions> CombineAstAsgDirector<R, O> {
(AstConsoleFunction::Assert(ast_expression), AsgConsoleFunction::Assert(asg_expression)) => {
AstConsoleFunction::Assert(self.reduce_expression(&ast_expression, asg_expression.get())?)
}
(AstConsoleFunction::Debug(ast_format), AsgConsoleFunction::Debug(asg_format))
| (AstConsoleFunction::Error(ast_format), AsgConsoleFunction::Error(asg_format))
| (AstConsoleFunction::Log(ast_format), AsgConsoleFunction::Log(asg_format)) => {
(AstConsoleFunction::Debug(ast_console_args), AsgConsoleFunction::Debug(asg_format))
| (AstConsoleFunction::Error(ast_console_args), AsgConsoleFunction::Error(asg_format))
| (AstConsoleFunction::Log(ast_console_args), AsgConsoleFunction::Log(asg_format)) => {
let mut parameters = vec![];
for (ast_parameter, asg_parameter) in ast_format.parameters.iter().zip(asg_format.parameters.iter()) {
for (ast_parameter, asg_parameter) in
ast_console_args.parameters.iter().zip(asg_format.parameters.iter())
{
parameters.push(self.reduce_expression(&ast_parameter, asg_parameter.get())?);
}
let formatted = FormatString {
parts: ast_format.parts.clone(),
let args = AstConsoleArgs {
string: ast_console_args.string.clone(),
parameters,
span: ast_format.span.clone(),
span: ast_console_args.span.clone(),
};
match &ast.function {
AstConsoleFunction::Debug(_) => AstConsoleFunction::Debug(formatted),
AstConsoleFunction::Error(_) => AstConsoleFunction::Error(formatted),
AstConsoleFunction::Log(_) => AstConsoleFunction::Log(formatted),
_ => return Err(ReducerError::impossible_console_assert_call(&ast_format.span)),
AstConsoleFunction::Debug(_) => AstConsoleFunction::Debug(args),
AstConsoleFunction::Error(_) => AstConsoleFunction::Error(args),
AstConsoleFunction::Log(_) => AstConsoleFunction::Log(args),
_ => return Err(ReducerError::impossible_console_assert_call(&ast_console_args.span)),
}
}
_ => ast.function.clone(),

View File

@ -20,6 +20,7 @@ use std::{
};
use leo_asg::*;
use leo_ast::{Ast, Program};
use leo_synthesizer::{CircuitSynthesizer, SerializedCircuit, SummarizedCircuit};
use leo_test_framework::{
runner::{Namespace, ParseType, Runner},
@ -28,7 +29,13 @@ use leo_test_framework::{
use serde_yaml::Value;
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
use leo_compiler::{compiler::Compiler, errors::CompilerError, targets::edwards_bls12::EdwardsGroupType, Output};
use crate::{
compiler::Compiler,
errors::CompilerError,
targets::edwards_bls12::EdwardsGroupType,
AstSnapshotOptions,
Output,
};
pub type EdwardsTestCompiler = Compiler<'static, Fq, EdwardsGroupType>;
// pub type EdwardsConstrainedValue = ConstrainedValue<'static, Fq, EdwardsGroupType>;
@ -39,9 +46,10 @@ pub(crate) fn make_test_context() -> AsgContext<'static> {
new_context(allocator)
}
fn new_compiler(path: PathBuf) -> EdwardsTestCompiler {
fn new_compiler(path: PathBuf, theorem_options: Option<AstSnapshotOptions>) -> EdwardsTestCompiler {
let program_name = "test".to_string();
let output_dir = PathBuf::from("/output/");
let output_dir = PathBuf::from("/tmp/output/");
std::fs::create_dir_all(output_dir.clone()).unwrap();
EdwardsTestCompiler::new(
program_name,
@ -49,13 +57,25 @@ fn new_compiler(path: PathBuf) -> EdwardsTestCompiler {
output_dir,
make_test_context(),
None,
None,
HashMap::new(),
theorem_options,
)
}
pub(crate) fn parse_program(program_string: &str) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler("compiler-test".into());
fn hash(input: String) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
let output = hasher.finalize();
hex::encode(&output[..])
}
pub(crate) fn parse_program(
program_string: &str,
theorem_options: Option<AstSnapshotOptions>,
) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler("compiler-test".into(), theorem_options);
compiler.parse_program_from_string(program_string)?;
@ -74,6 +94,9 @@ struct OutputItem {
struct CompileOutput {
pub circuit: SummarizedCircuit,
pub output: Vec<OutputItem>,
pub initial_ast: String,
pub canonicalized_ast: String,
pub type_inferenced_ast: String,
}
impl Namespace for CompileNamespace {
@ -96,24 +119,30 @@ impl Namespace for CompileNamespace {
// })
// .unwrap_or(test.path.clone());
let parsed = parse_program(&test.content).map_err(|x| x.to_string())?;
let parsed = parse_program(
&test.content,
Some(AstSnapshotOptions {
initial: true,
canonicalized: true,
type_inferenced: true,
}),
)
.map_err(|x| x.to_string())?;
// (name, content)
let mut inputs = vec![];
if let Some(input) = test.config.get("inputs") {
if let Value::Sequence(field) = input {
for map in field {
for (name, value) in map.as_mapping().unwrap().iter() {
// Try to parse string from 'inputs' map, else fail
let value = if let serde_yaml::Value::String(value) = value {
value
} else {
return Err("Expected string in 'inputs' map".to_string());
};
if let Some(Value::Sequence(field)) = test.config.get("inputs") {
for map in field {
for (name, value) in map.as_mapping().unwrap().iter() {
// Try to parse string from 'inputs' map, else fail
let value = if let serde_yaml::Value::String(value) = value {
value
} else {
return Err("Expected string in 'inputs' map".to_string());
};
inputs.push((name.as_str().unwrap().to_string(), value.clone()));
}
inputs.push((name.as_str().unwrap().to_string(), value.clone()));
}
}
}
@ -180,15 +209,38 @@ impl Namespace for CompileNamespace {
} else {
last_circuit = Some(circuit);
}
output_items.push(OutputItem {
input_file: input.0,
output,
});
}
let initial_ast: String = hash(
Ast::from_json_file("/tmp/output/initial_ast.json".into())
.unwrap_or_else(|_| Ast::new(Program::new("Error reading initial theorem.".to_string())))
.to_json_string()
.unwrap_or_else(|_| "Error converting ast to string.".to_string()),
);
let canonicalized_ast: String = hash(
Ast::from_json_file("/tmp/output/canonicalization_ast.json".into())
.unwrap_or_else(|_| Ast::new(Program::new("Error reading canonicalized theorem.".to_string())))
.to_json_string()
.unwrap_or_else(|_| "Error converting ast to string.".to_string()),
);
let type_inferenced_ast = hash(
Ast::from_json_file("/tmp/output/type_inferenced_ast.json".into())
.unwrap_or_else(|_| Ast::new(Program::new("Error reading type inferenced theorem.".to_string())))
.to_json_string()
.unwrap_or_else(|_| "Error converting ast to string.".to_string()),
);
let final_output = CompileOutput {
circuit: last_circuit.unwrap(),
output: output_items,
initial_ast,
canonicalized_ast,
type_inferenced_ast,
};
Ok(serde_yaml::to_value(&final_output).expect("serialization failed"))
}

View File

@ -1,359 +0,0 @@
{
"name": "",
"expected_input": [],
"imports": [],
"circuits": {},
"global_consts": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}",
"input": [
{
"Variable": {
"identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}",
"const_": false,
"mutable": true,
"type_": {
"Array": [
{
"Array": [
"Group",
[
{
"value": "1"
}
]
]
},
[
{
"value": "2"
}
]
]
},
"span": {
"line_start": 1,
"line_stop": 1,
"col_start": 15,
"col_stop": 16,
"path": "",
"content": "function main(a: [group; (2, 1)]) {"
}
}
}
],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let b = [true; (6, 5, 4, 3, 2)];\\\"}\"}",
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
],
"type_": null,
"value": {
"ArrayInit": {
"element": {
"ArrayInit": {
"element": {
"ArrayInit": {
"element": {
"ArrayInit": {
"element": {
"ArrayInit": {
"element": {
"Value": {
"Boolean": [
"true",
{
"line_start": 2,
"line_stop": 2,
"col_start": 12,
"col_stop": 16,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
]
}
},
"dimensions": [
{
"value": "2"
}
],
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
"dimensions": [
{
"value": "3"
}
],
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
"dimensions": [
{
"value": "4"
}
],
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
"dimensions": [
{
"value": "5"
}
],
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
"dimensions": [
{
"value": "6"
}
],
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 3,
"col_stop": 34,
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let c: [u32; (1, 2)] = [0u32; (1, 2)];\\\"}\"}",
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
],
"type_": {
"Array": [
{
"Array": [
{
"IntegerType": "U32"
},
[
{
"value": "2"
}
]
]
},
[
{
"value": "1"
}
]
]
},
"value": {
"ArrayInit": {
"element": {
"ArrayInit": {
"element": {
"Value": {
"Integer": [
"U32",
"0",
{
"line_start": 3,
"line_stop": 3,
"col_start": 27,
"col_stop": 31,
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
]
}
},
"dimensions": [
{
"value": "2"
}
],
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 26,
"col_stop": 40,
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
"dimensions": [
{
"value": "1"
}
],
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 26,
"col_stop": 40,
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 3,
"col_stop": 40,
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let d = [0i8; (1)];\\\"}\"}",
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let d = [0i8; (1)];"
}
}
],
"type_": null,
"value": {
"ArrayInit": {
"element": {
"Value": {
"Integer": [
"I8",
"0",
{
"line_start": 4,
"line_stop": 4,
"col_start": 12,
"col_stop": 15,
"path": "",
"content": " let d = [0i8; (1)];"
}
]
}
},
"dimensions": [
{
"value": "1"
}
],
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 11,
"col_stop": 21,
"path": "",
"content": " let d = [0i8; (1)];"
}
}
},
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 3,
"col_stop": 21,
"path": "",
"content": " let d = [0i8; (1)];"
}
}
}
],
"span": {
"line_start": 1,
"line_stop": 7,
"col_start": 35,
"col_stop": 2,
"path": "",
"content": "function main(a: [group; (2, 1)]) {\n...\n}"
}
},
"span": {
"line_start": 1,
"line_stop": 7,
"col_start": 1,
"col_stop": 2,
"path": "",
"content": "function main(a: [group; (2, 1)]) {\n...\n}\n\n\n\n"
}
}
}
}

View File

@ -1,7 +0,0 @@
function main(a: [group; (2, 1)]) {
let b = [true; (6, 5, 4, 3, 2)];
let c: [u32; (1, 2)] = [0u32; (1, 2)];
let d = [0i8; (1)];
// let d = [true; 0];
// let e = [true; (0)];
}

View File

@ -1,3 +0,0 @@
function main() {
let a = [true; (0)];
}

View File

@ -1,438 +0,0 @@
{
"name": "",
"expected_input": [],
"imports": [],
"circuits": {
"{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}": {
"circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"CircuitVariable": [
"{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: u32;\\\"}\"}",
{
"IntegerType": "U32"
}
]
},
{
"CircuitFunction": {
"annotations": [],
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" function new() -> Self {\\\"}\"}",
"input": [],
"output": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}"
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let new: Self = Self {\\\"}\"}",
"span": {
"line_start": 5,
"line_stop": 5,
"col_start": 9,
"col_stop": 12,
"path": "",
"content": " let new: Self = Self {"
}
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}"
},
"value": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: 1u32\\\"}\"}",
"expression": {
"Value": {
"Integer": [
"U32",
"1",
{
"line_start": 6,
"line_stop": 6,
"col_start": 10,
"col_stop": 14,
"path": "",
"content": " x: 1u32"
}
]
}
}
}
],
"span": {
"line_start": 5,
"line_stop": 7,
"col_start": 21,
"col_stop": 6,
"path": "",
"content": " let new: Self = Self {\n...\n };"
}
}
},
"span": {
"line_start": 5,
"line_stop": 7,
"col_start": 5,
"col_stop": 6,
"path": "",
"content": " let new: Self = Self {\n...\n };"
}
}
},
{
"Return": {
"expression": {
"Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" return new;\\\"}\"}"
},
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 5,
"col_stop": 15,
"path": "",
"content": " return new;"
}
}
}
],
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 26,
"col_stop": 4,
"path": "",
"content": " function new() -> Self {\n...\n }"
}
},
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 3,
"col_stop": 4,
"path": "",
"content": " function new() -> Self {\n...\n }\n\n\n\n"
}
}
},
{
"CircuitFunction": {
"annotations": [],
"identifier": "{\"name\":\"etc\",\"span\":\"{\\\"line_start\\\":12,\\\"line_stop\\\":12,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" function etc() {\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":6,\\\"col_stop\\\":7,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}",
"accesses": [
{
"ArrayIndex": {
"Call": {
"function": {
"CircuitMemberAccess": {
"circuit": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":14,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}",
"expression": {
"Value": {
"Implicit": [
"0",
{
"line_start": 13,
"line_stop": 13,
"col_start": 17,
"col_stop": 18,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
]
}
}
}
],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 19,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"name": "{\"name\":\"func\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":20,\\\"col_stop\\\":24,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}",
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 24,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"arguments": [],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 26,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
}
}
],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 6,
"col_stop": 27,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
},
"value": {
"Binary": {
"left": {
"ArrayAccess": {
"array": {
"Identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":6,\\\"col_stop\\\":7,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}"
},
"index": {
"Call": {
"function": {
"CircuitMemberAccess": {
"circuit": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":14,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}",
"expression": {
"Value": {
"Implicit": [
"0",
{
"line_start": 13,
"line_stop": 13,
"col_start": 17,
"col_stop": 18,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
]
}
}
}
],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 19,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"name": "{\"name\":\"func\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":20,\\\"col_stop\\\":24,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[Self {x: 0}.func()] += 2;\\\"}\"}",
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 24,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"arguments": [],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 8,
"col_stop": 26,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 6,
"col_stop": 32,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"right": {
"Value": {
"Implicit": [
"2",
{
"line_start": 13,
"line_stop": 13,
"col_start": 31,
"col_stop": 32,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
]
}
},
"op": "Add",
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 6,
"col_stop": 32,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
},
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 6,
"col_stop": 32,
"path": "",
"content": " y[Self {x: 0}.func()] += 2;"
}
}
}
],
"span": {
"line_start": 12,
"line_stop": 14,
"col_start": 18,
"col_stop": 4,
"path": "",
"content": " function etc() {\n...\n }"
}
},
"span": {
"line_start": 12,
"line_stop": 14,
"col_start": 3,
"col_stop": 4,
"path": "",
"content": " function etc() {\n...\n }"
}
}
}
]
}
},
"global_consts": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}",
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 7,
"col_stop": 10,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}"
},
"value": {
"Call": {
"function": {
"CircuitStaticFunctionAccess": {
"circuit": {
"Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}"
},
"name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}",
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 18,
"col_stop": 26,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
},
"arguments": [],
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 18,
"col_stop": 28,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
},
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 3,
"col_stop": 28,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
}
],
"span": {
"line_start": 17,
"line_stop": 19,
"col_start": 17,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n}"
}
},
"span": {
"line_start": 17,
"line_stop": 19,
"col_start": 1,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n}"
}
}
}
}

View File

@ -1,19 +0,0 @@
circuit Foo {
x: u32;
function new() -> Self {
let new: Self = Self {
x: 1u32
};
return new;
}
function etc() {
y[Self {x: 0}.func()] += 2;
}
}
function main() {
let foo: Foo = Foo::new();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
function main () {
let x = [1u32; 5];
x[..2] += 1;
}

View File

@ -1,2 +0,0 @@
[main]
a: [group; (2, 1)] = [1group; (2, 1)];

View File

@ -1,97 +0,0 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::parse_program;
use leo_ast::Ast;
use leo_parser::parser;
pub fn parse_program_ast(file_string: &str) -> Ast {
const TEST_PROGRAM_PATH: &str = "";
let test_program_file_path = std::path::PathBuf::from(TEST_PROGRAM_PATH);
let mut ast = Ast::new(
parser::parse(test_program_file_path.to_str().expect("unwrap fail"), &file_string)
.expect("Failed to parse file."),
);
ast.canonicalize().expect("Failed to canonicalize program.");
ast
}
#[test]
fn test_big_self_in_circuit_replacement() {
// Check program is valid.
let program_string = include_str!("big_self_in_circuit_replacement.leo");
// Check we get expected ast.
let ast = parse_program_ast(program_string);
let expected_json = include_str!("big_self_in_circuit_replacement.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}
#[test]
fn test_big_self_outside_circuit_fail() {
// Check program is invalid.
let program_string = include_str!("big_self_outside_circuit_fail.leo");
let program = parse_program(program_string);
assert!(program.is_err());
}
#[test]
fn test_array_expansion() {
let program_string = include_str!("array_expansion.leo");
let ast = parse_program_ast(program_string);
let expected_json = include_str!("array_expansion.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}
#[test]
fn test_array_size_zero_fail() {
let program_string = include_str!("array_size_zero_fail.leo");
let program = parse_program(program_string);
assert!(program.is_err());
}
#[test]
fn test_compound_assignment() {
let program_string = include_str!("compound_assignment.leo");
let ast = parse_program_ast(program_string);
let expected_json = include_str!("compound_assignment.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}
#[test]
fn test_illegal_array_range_fail() {
// Check program is invalid.
let program_string = include_str!("illegal_array_range_fail.leo");
let program = parse_program(program_string);
assert!(program.is_err());
}
#[test]
fn test_string_transformation() {
let program_string = include_str!("string_transformation.leo");
let ast = parse_program_ast(program_string);
let expected_json = include_str!("string_transformation.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +0,0 @@
function main() {
let s = "\u{2764}ello, World!\u{DDDD}";
s[..2] = "he";
let x = false;
x = "test1" == "test2";
let z = [1u8, 2u8, 3u8, 4u8];
z[0.."test" == "test"? 2 : 2] = x[0..2];
}

View File

@ -1 +0,0 @@
[registers]

View File

@ -1,131 +0,0 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
// allow the use of EdwardsTestCompiler::parse_program_from_string for tests
#![allow(deprecated)]
pub mod canonicalization;
pub mod type_inference;
use leo_asg::{new_alloc_context, new_context, AsgContext};
use leo_compiler::{
compiler::Compiler,
errors::CompilerError,
group::targets::edwards_bls12::EdwardsGroupType,
ConstrainedValue,
OutputBytes,
};
use snarkvm_curves::edwards_bls12::Fq;
use snarkvm_r1cs::TestConstraintSystem;
use std::{collections::HashMap, path::PathBuf};
pub const TEST_OUTPUT_DIRECTORY: &str = "/output/";
const EMPTY_FILE: &str = "";
pub type EdwardsTestCompiler = Compiler<'static, Fq, EdwardsGroupType>;
pub type EdwardsConstrainedValue = ConstrainedValue<'static, Fq, EdwardsGroupType>;
//convenience function for tests, leaks memory
pub(crate) fn make_test_context() -> AsgContext<'static> {
let allocator = Box::leak(Box::new(new_alloc_context()));
new_context(allocator)
}
fn new_compiler() -> EdwardsTestCompiler {
let program_name = "test".to_string();
let path = PathBuf::from("/test/src/main.leo");
let output_dir = PathBuf::from(TEST_OUTPUT_DIRECTORY);
EdwardsTestCompiler::new(
program_name,
path,
output_dir,
make_test_context(),
None,
None,
HashMap::new(),
)
}
pub(crate) fn parse_program(program_string: &str) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
compiler.parse_program_from_string(program_string)?;
Ok(compiler)
}
pub fn parse_program_with_input(
program_string: &str,
input_string: &str,
) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
let path = PathBuf::new();
compiler.parse_input(input_string, &path, EMPTY_FILE, &path)?;
compiler.parse_program_from_string(program_string)?;
Ok(compiler)
}
pub fn parse_program_with_state(
program_string: &str,
state_string: &str,
) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
let path = PathBuf::new();
compiler.parse_input(EMPTY_FILE, &path, state_string, &path)?;
compiler.parse_program_from_string(program_string)?;
Ok(compiler)
}
pub fn parse_program_with_input_and_state(
program_string: &str,
input_string: &str,
state_string: &str,
) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
let path = PathBuf::new();
compiler.parse_input(input_string, &path, state_string, &path)?;
compiler.parse_program_from_string(&program_string)?;
Ok(compiler)
}
pub(crate) fn get_output(program: EdwardsTestCompiler) -> OutputBytes {
// synthesize the circuit on the test constraint system
let mut cs = TestConstraintSystem::<Fq>::new();
let output = program.compile_constraints(&mut cs).unwrap();
// assert the constraint system is satisfied
assert!(cs.is_satisfied());
output.into()
}
pub(crate) fn assert_satisfied(program: EdwardsTestCompiler) {
let empty_output_bytes = include_bytes!("compiler_output/empty.out");
let res = get_output(program);
// assert that the output is empty
assert_eq!(empty_output_bytes, res.bytes().as_slice());
}

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
circuit Foo {}
function two() -> u8 {
return 2u8;
}
const ONE = 1u8;
function main() {
const a = 1u8;
const b = 1field;
const c = 1group;
const d = (0, 1)group;
const e = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
const f = two();
const g = [0u8; (3, 2)];
const h = [[0u8; 3]; 2];
const i = [1u8, 1u8, 1u8];
const j = true;
const k = (1u8, 1u8);
const l = (1u8, 1u8, true);
const m = Foo {};
const n = 'a';
const o = "Hello, World!";
const p = [...[1u8], ...[2u8]];
const q = [...p, 3u8] == [1u8, 2u8, 3u8];
}

View File

@ -1,243 +0,0 @@
{
"name": "",
"expected_input": [],
"imports": [],
"circuits": {},
"global_consts": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let x = 10u16;\\\"}\"}",
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 9,
"col_stop": 10,
"path": "",
"content": " let x = 10u16;"
}
}
],
"type_": {
"IntegerType": "U16"
},
"value": {
"Value": {
"Integer": [
"U16",
"10",
{
"line_start": 2,
"line_stop": 2,
"col_start": 13,
"col_stop": 18,
"path": "",
"content": " let x = 10u16;"
}
]
}
},
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 5,
"col_stop": 18,
"path": "",
"content": " let x = 10u16;"
}
}
},
{
"Iteration": {
"variable": "{\"name\":\"i\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" for i in 0..3 {\\\"}\"}",
"start": {
"Value": {
"Integer": [
"U32",
"0",
{
"line_start": 3,
"line_stop": 3,
"col_start": 14,
"col_stop": 15,
"path": "",
"content": " for i in 0..3 {"
}
]
}
},
"stop": {
"Value": {
"Integer": [
"U32",
"3",
{
"line_start": 3,
"line_stop": 3,
"col_start": 17,
"col_stop": 18,
"path": "",
"content": " for i in 0..3 {"
}
]
}
},
"block": {
"statements": [
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x -= 1;\\\"}\"}",
"accesses": [],
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 9,
"col_stop": 10,
"path": "",
"content": " x -= 1;"
}
},
"value": {
"Binary": {
"left": {
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x -= 1;\\\"}\"}"
},
"right": {
"Value": {
"Integer": [
"U16",
"1",
{
"line_start": 4,
"line_stop": 4,
"col_start": 14,
"col_stop": 15,
"path": "",
"content": " x -= 1;"
}
]
}
},
"op": "Sub",
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 9,
"col_stop": 15,
"path": "",
"content": " x -= 1;"
}
}
},
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 9,
"col_stop": 15,
"path": "",
"content": " x -= 1;"
}
}
}
],
"span": {
"line_start": 3,
"line_stop": 5,
"col_start": 19,
"col_stop": 6,
"path": "",
"content": " for i in 0..3 {\n...\n }"
}
},
"span": {
"line_start": 3,
"line_stop": 5,
"col_start": 5,
"col_stop": 6,
"path": "",
"content": " for i in 0..3 {\n...\n }"
}
}
},
{
"Console": {
"function": {
"Assert": {
"Binary": {
"left": {
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":20,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(x == 7u16);\\\"}\"}"
},
"right": {
"Value": {
"Integer": [
"U16",
"7",
{
"line_start": 6,
"line_stop": 6,
"col_start": 25,
"col_stop": 29,
"path": "",
"content": " console.assert(x == 7u16);"
}
]
}
},
"op": "Eq",
"span": {
"line_start": 6,
"line_stop": 6,
"col_start": 20,
"col_stop": 29,
"path": "",
"content": " console.assert(x == 7u16);"
}
}
}
},
"span": {
"line_start": 6,
"line_stop": 6,
"col_start": 5,
"col_stop": 29,
"path": "",
"content": " console.assert(x == 7u16);"
}
}
}
],
"span": {
"line_start": 1,
"line_stop": 7,
"col_start": 17,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n}"
}
},
"span": {
"line_start": 1,
"line_stop": 7,
"col_start": 1,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n}\n\n\n\n"
}
}
}
}

View File

@ -1,7 +0,0 @@
function main() {
let x = 10u16;
for i in 0..3 {
x -= 1;
}
console.assert(x == 7u16);
}

View File

@ -1,85 +0,0 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{assert_satisfied, parse_program};
#[allow(unused)]
use leo_asg::{new_context, Asg, AsgContext};
use leo_ast::Ast;
use leo_compiler::TypeInferencePhase;
use leo_imports::ImportParser;
use leo_parser::parser;
thread_local! {
static THREAD_GLOBAL_CONTEXT: AsgContext<'static> = {
let leaked = Box::leak(Box::new(leo_asg::new_alloc_context()));
leo_asg::new_context(leaked)
}
}
pub fn thread_leaked_context() -> AsgContext<'static> {
THREAD_GLOBAL_CONTEXT.with(|f| *f)
}
pub fn parse_program_ast(file_string: &str) -> Ast {
const TEST_PROGRAM_PATH: &str = "";
let test_program_file_path = std::path::PathBuf::from(TEST_PROGRAM_PATH);
let mut ast = Ast::new(
parser::parse(test_program_file_path.to_str().expect("unwrap fail"), &file_string)
.expect("Failed to parse file."),
);
ast.canonicalize().expect("Failed to canonicalize program.");
let program = ast.clone().into_repr();
let asg = Asg::new(thread_leaked_context(), &program, &mut ImportParser::default())
.expect("Failed to create ASG from AST");
let new_ast = TypeInferencePhase::default()
.phase_ast(&program, &asg.into_repr())
.expect("Failed to produce type inference ast.");
new_ast
}
#[test]
fn test_basic() {
// Check program is valid.
let program_string = include_str!("basic.leo");
let program = parse_program(program_string).unwrap();
assert_satisfied(program);
// Check we get expected ast.
let ast = parse_program_ast(program_string);
let expected_json = include_str!("basic.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}
#[test]
fn test_for_loop_and_compound() {
// Check program is valid.
let program_string = include_str!("for_loop_and_compound.leo");
let program = parse_program(program_string).unwrap();
assert_satisfied(program);
// Check we get expected ast.
let ast = parse_program_ast(program_string);
let expected_json = include_str!("for_loop_and_compound.json");
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
assert_eq!(expected_ast, ast);
}

View File

@ -25,9 +25,7 @@ that we suggest few changes to Leo CLI and Manifest:
- allow custom names for imports to manually resolve name conflicts;
- add "curve" and "proving system" sections to the Manifest;
- add "include" and "exclude" parameters for "proving system" and "curve";
Later this solution can be improved by adding a lock-file which would lock
imported packages based on both their contents and version.
- add a lock file which would store imported dependencies and their relations;
# Motivation
@ -109,12 +107,7 @@ To support updated Manifest new command should be added to Leo CLI.
```bash
# pull imports
leo install
```
Alternatively it can be called `pull`.
```
leo pull
leo fetch
```
## Imports Restructurization
@ -155,6 +148,44 @@ first-program => author1-program@0.1.0
second-program => author2-program2@1.0.4
```
## Leo.lock
For imports map to be generated and read by the Leo binary and then by the Leo compiler,
a lock file needs to be created. Lock file should be generated by the `leo fetch` command,
which will pull the dependencies, process their manifests, and put the required information
to the file in the root directory of the program called `Leo.lock`.
Suggested structure of this file is similar to the Cargo.lock file:
```
[[package]]
name = "suit-mk2"
version = "0.2.0"
author = "ironman"
import_name = "suit-mk2"
[package.dependencies]
garbage = "ironman-suit@0.1.0"
[[package]]
name = "suit"
version = "0.1.0"
author = "ironman"
import_name = "garbage"
```
In the example above, you can see that all program dependencies are defined as an
array called `package`. Each of the dependencies contains main information about
it, including the `import_name` field which is the imported package's name in
the Leo program. Also, it stores relationships between these dependencies in the
field `dependencies`.
The format described here allows the Leo binary to form an imports map which can be
passed to the compiler.
It is important to note that Leo.lock file is created only when a package has dependencies.
For programs with no dependencies, a lock file is not required and not created.
## Recursive Dependencies
This improvement introduces recursive dependencies. To solve this case preemptively

View File

@ -94,6 +94,26 @@ for i in 0..5 {}
for i in 0..=5 {}
```
## Step and Direction
We remark that the step of both counting-up and counting-down loops is implicitly 1;
that is, the loop variable is incremented or decremented by 1.
Whether the loop counts up or down is determined by how the starting and ending bounds compare.
Note that the bounds are not necessarily literals;
they may be more complex `const` expressions, and thus in general their values are resolved at code flattening time.
Because of the type restrictions on bounds, their values are always non-negative integers.
If `S` is the integer value of the starting bound and `E` is the integer value of the ending bound,
there are several cases to consider:
1. If `S == E` and the ending bound is exclusive, there is no actual loop; the range is empty.
2. If `S == E` and the ending bound is inclusive, the loop consists of just one iteration; the loop counts neither up nor down.
3. If `S < E` and the ending bound is exclusive, the loop counts up, from `S` to `E-1`.
4. If `S < E` and the ending bound is inclusive, the loop counts up, from `S` to `E`.
5. If `S > E` and the ending bound is exclusive, the loop counts down, from `S` to `E+1`.
6. If `S > E` and the ending bound is inclusive, the loop counts down, from `S` to `E`.
Cases 3 and 5 consist of one or more iterations; cases 4 and 6 consist of two or more iterations.
## Example
The code example demostrated in the Motivation part of this document

View File

@ -1 +1,2 @@
abnf-grammar.txt text eol=crlf
abnf-grammar.txt text eol=crlf
format-abnf-grammar.txt text eol=crlf

Binary file not shown.

Binary file not shown.

View File

@ -555,11 +555,8 @@ unicode-character-escape = %s"\u{" 1*6hexadecimal-digit "}"
; A string literal consists of one or more elements surrounded by double quotes.
; Each element is any character other than double quote or backslash,
; or an escape among the same ones used for elements of character literals.
; There must be at least one element
; because string literals denote character arrays,
; and arrays must not be empty.
string-literal = double-quote 1*string-literal-element double-quote
string-literal = double-quote *string-literal-element double-quote
string-literal-element = not-double-quote-or-backslash
/ simple-character-escape

View File

@ -0,0 +1,50 @@
; Copyright (C) 2019-2021 Aleo Systems Inc.
; This file is part of the Leo library.
; The Leo library is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; The Leo library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
; You should have received a copy of the GNU General Public License
; along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Background on ABNF
; ------------------
; ABNF is an Internet standard:
; for more info please checkout the
; [README](./README.md) in this directory.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Format String
; -------------------
; This ABNF grammar consists of one grammar:
; that describes how a Leo string-literal is parsed
; for formatting. Meaning in this context
; all characters are already parsed and we don't
; have to worry about escapes or etc.
not-brace = %x0-7A / %x7C / %x7E-10FFFF ; anything but { or }
format-string-container = "{}"
format-string-open-brace = "{{"
format-string-close-brace = "}}"
format-string-element = not-brace
/ format-string-container
/ format-string-open-brace
/ format-string-close-brace
format-string = *format-string-element

View File

@ -40,7 +40,7 @@
//
use abnf::types::{Node, Rule};
use anyhow::Result;
use anyhow::{anyhow, Result};
use std::collections::{HashMap, HashSet};
/// Processor's scope. Used when code block or definition starts or ends.
@ -197,18 +197,24 @@ fn parse_abnf_node(node: &Node, sum: &mut Vec<String>) {
fn main() -> Result<()> {
// Take Leo ABNF grammar file.
let grammar = include_str!("../abnf-grammar.txt");
let args: Vec<String> = std::env::args().collect();
let abnf_path = if let Some(path) = args.get(1) {
std::path::Path::new(path)
} else {
return Err(anyhow!("Usage Error: expects one argument to abnf file to convert."));
};
let grammar = std::fs::read_to_string(abnf_path)?;
// Parse ABNF to get list of all definitions.
// Rust ABNF does not provide support for `%s` (case sensitive strings, part of
// the standard); so we need to remove all occurrences before parsing.
let parsed = abnf::rulelist(&str::replace(grammar, "%s", "")).map_err(|e| {
let parsed = abnf::rulelist(&str::replace(&grammar, "%s", "")).map_err(|e| {
eprintln!("{}", &e);
anyhow::anyhow!(e)
})?;
// Init parser and run it. That's it.
let mut parser = Processor::new(grammar, parsed);
let mut parser = Processor::new(&grammar, parsed);
parser.process();
// Print result of conversion to STDOUT.

View File

@ -18,8 +18,8 @@ use crate::{commands::Command, context::Context};
use leo_compiler::{
compiler::{thread_leaked_context, Compiler},
group::targets::edwards_bls12::EdwardsGroupType,
AstSnapshotOptions,
CompilerOptions,
TheoremOptions,
};
use leo_package::{
inputs::*,
@ -46,14 +46,14 @@ pub struct BuildOptions {
pub disable_code_elimination: bool,
#[structopt(long, help = "Disable all compiler optimizations")]
pub disable_all_optimizations: bool,
#[structopt(long, help = "Writes all theorem input AST files.")]
pub enable_all_theorems: bool,
#[structopt(long, help = "Writes AST files needed for the initial theorem before any changes.")]
pub enable_initial_theorem: bool,
#[structopt(long, help = "Writes AST files needed for canonicalization theorem.")]
pub enable_canonicalized_theorem: bool,
#[structopt(long, help = "Writes AST files needed for type inference theorem.")]
pub enable_type_inferenced_theorem: bool,
#[structopt(long, help = "Writes all AST snapshots for the different compiler phases.")]
pub enable_all_ast_snapshots: bool,
#[structopt(long, help = "Writes AST snapshot of the initial parse.")]
pub enable_initial_ast_snapshot: bool,
#[structopt(long, help = "Writes AST snapshot after the canonicalization phase.")]
pub enable_canonicalized_ast_snapshot: bool,
#[structopt(long, help = "Writes AST snapshot after the type inference phase.")]
pub enable_type_inferenced_ast_snapshot: bool,
}
impl Default for BuildOptions {
@ -63,10 +63,10 @@ impl Default for BuildOptions {
disable_constant_folding: true,
disable_code_elimination: true,
disable_all_optimizations: true,
enable_all_theorems: false,
enable_initial_theorem: false,
enable_canonicalized_theorem: false,
enable_type_inferenced_theorem: false,
enable_all_ast_snapshots: false,
enable_initial_ast_snapshot: false,
enable_canonicalized_ast_snapshot: false,
enable_type_inferenced_ast_snapshot: false,
}
}
}
@ -89,19 +89,19 @@ impl From<BuildOptions> for CompilerOptions {
}
}
impl From<BuildOptions> for TheoremOptions {
impl From<BuildOptions> for AstSnapshotOptions {
fn from(options: BuildOptions) -> Self {
if options.enable_all_theorems {
TheoremOptions {
if options.enable_all_ast_snapshots {
AstSnapshotOptions {
initial: true,
canonicalized: true,
type_inferenced: true,
}
} else {
TheoremOptions {
initial: options.enable_initial_theorem,
canonicalized: options.enable_canonicalized_theorem,
type_inferenced: options.enable_type_inferenced_theorem,
AstSnapshotOptions {
initial: options.enable_initial_ast_snapshot,
canonicalized: options.enable_canonicalized_ast_snapshot,
type_inferenced: options.enable_type_inferenced_ast_snapshot,
}
}
}
@ -174,7 +174,7 @@ impl Command for Build {
// Log compilation of files to console
tracing::info!("Compiling main program... ({:?})", main_file_path);
if self.compiler_options.disable_canonicalization && self.compiler_options.enable_canonicalized_theorem {
if self.compiler_options.disable_canonicalization && self.compiler_options.enable_canonicalized_ast_snapshot {
tracing::warn!(
"Can not ask for canonicalization theorem without having canonicalization compiler feature enabled."
);
@ -197,8 +197,8 @@ impl Command for Build {
&state_path,
thread_leaked_context(),
Some(self.compiler_options.clone().into()),
Some(self.compiler_options.into()),
imports_map,
Some(self.compiler_options.into()),
)?;
// Compute the current program checksum

View File

@ -112,8 +112,8 @@ impl Command for Test {
output_directory.clone(),
thread_leaked_context(),
Some(self.compiler_options.clone().into()),
Some(self.compiler_options.clone().into()),
std::collections::HashMap::new(),
Some(self.compiler_options.clone().into()),
)?;
let temporary_program = program;

124
parser/README.md Normal file
View File

@ -0,0 +1,124 @@
# Leo Parser
[![Crates.io](https://img.shields.io/crates/v/leo-parser.svg?color=neon)](https://crates.io/crates/leo-parser)
[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](../AUTHORS)
[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md)
This directory contains the code to tokenize, lex and parse Leo files to the [Leo AST](./../ast/README.md).
## Tokenizer
The tokenizer contains all tokens in Leo.
It also decides which tokens are keywords.
Meaning that keywords are a subset of tokens.
The lexer goes through character by character as bytes, and converts the bytes into the tokens.
### Tokens
Bolded ones are also keywords.
#### Literals
- CommentLine
- CommentBlock
- StringLit
- Ident
- Int
- **True**
- **False**
- AddressLit
- CharLit
#### Symbols
- At
- Not
- And
- Or
- Eq
- NotEq
- Lt
- LtEq
- Gt
- GtEq
- Add
- Minus
- Mul
- Div
- Exp
- Assign
- AddEq
- MinusEq
- MulEq
- DivEq
- ExpEq
- LeftParen
- RightParen
- LeftSquare
- RightSquare
- LeftCurly
- RightCurly
- Comma
- Dot
- DotDot
- DotDotDot
- Semicolon
- Colon
- DoubleColon
- Question
- Arrow
- Underscore
#### Types
- **U8**
- **U16**
- **U32**
- **U64**
- **U128**
- **I8**
- **I16**
- **I32**
- **I64**
- **I128**
- **Field**
- **Group**
- **Bool**
- **Address**
- **Char**
- **BigSelf**
#### Words
- **Input**
- **LittleSelf**
- **Import**
- **As**
- **Circuit**
- **Console**
- **Const**
- **Else**
- **For**
- **Function**
- **If**
- **In**
- **Let**
- **Mut**
- **Return**
- **Static**
- **String**
#### Meta
- Eof
## Parser
The parser converts the tokens to the [Leo AST](./../ast/README.md).
The parser is broken down to different files that correspond to different aspects of the AST:
- [File](./src/parser/file.rs) - Parses the top level nodes in Leo.
- [Types](./src/parser/type_.rs) - Parses the type declarations in Leo.
- [Statements](./src/parser/statement.rs) - Parses the different kinds of statements.
- [Expressions](./src/parser/expression.rs) - Parses the different kinds of expressions.
For more information on those please read the Leo AST README, linked above.
## Grammar Relation
All function and token names are as close as possible to the [Leo Grammar](./../grammar/README.md)

View File

@ -232,9 +232,9 @@ impl ParserContext {
}
///
/// Returns a [`FormatString`] AST node if the next tokens represent a formatted string.
/// Returns a [`ConsoleArgs`] AST node if the next tokens represent a formatted string.
///
pub fn parse_formatted_string(&mut self) -> SyntaxResult<FormatString> {
pub fn parse_console_args(&mut self) -> SyntaxResult<ConsoleArgs> {
let start_span;
let string = match self.expect_any()? {
SpannedToken {
@ -247,7 +247,7 @@ impl ParserContext {
SpannedToken { token, span } => return Err(SyntaxError::unexpected_str(&token, "formatted string", &span)),
};
let parts = FormatStringPart::from_string(string);
// let parts = FormatStringPart::from_string(string);
let mut parameters = Vec::new();
while self.eat(Token::Comma).is_some() {
@ -255,8 +255,8 @@ impl ParserContext {
parameters.push(param);
}
Ok(FormatString {
parts,
Ok(ConsoleArgs {
string,
span: &start_span + parameters.last().map(|x| x.span()).unwrap_or(&start_span),
parameters,
})
@ -275,9 +275,9 @@ impl ParserContext {
let expr = self.parse_expression()?;
ConsoleFunction::Assert(expr)
}
"debug" => ConsoleFunction::Debug(self.parse_formatted_string()?),
"error" => ConsoleFunction::Error(self.parse_formatted_string()?),
"log" => ConsoleFunction::Log(self.parse_formatted_string()?),
"debug" => ConsoleFunction::Debug(self.parse_console_args()?),
"error" => ConsoleFunction::Error(self.parse_console_args()?),
"log" => ConsoleFunction::Log(self.parse_console_args()?),
x => {
return Err(SyntaxError::unexpected_ident(
&x,

View File

@ -280,7 +280,7 @@ impl Token {
}
}
if i == input.len() || i == 1 || !end {
if i == input.len() || !end {
return (0, None);
}

View File

@ -58,9 +58,8 @@ pub enum Token {
AddressLit(#[serde(with = "leo_ast::common::tendril_json")] StrTendril),
CharLit(Char),
At,
// Symbols
At,
Not,
And,
Or,

View File

@ -0,0 +1,12 @@
/*
namespace: Compile
expectation: Fail
input_file: input/array_range_access_fail.in
*/
function main (
const x: u32
) {
const y = [1u8; 3];
const z: [u8; 2] = y[..1u32][..x];
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Fail
input_file: input/dummy.in
*/
function main() {
let a = [true; (0)];
}

View File

@ -0,0 +1,2 @@
[constants]
x: u32 = 1u32;

View File

@ -0,0 +1,27 @@
/*
namespace: Compile
expectation: Pass
input_file: input/dummy.in
*/
circuit Foo {
x: u32;
function new() -> Self {
let new: Self = Self {
x: 1u32
};
return new;
}
function etc() {
let y = [0u32, 1, 2, 3];
y[Self {x: 0}.x] += 2;
}
}
function main(y: bool) -> bool {
let foo: Foo = Foo::new();
return foo.x == 1u32 && y;
}

View File

@ -1,3 +1,9 @@
/*
namespace: Compile
expectation: Fail
input_file: input/dummy.in
*/
circuit Foo {
x: u32;

View File

@ -1,3 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/dummy.in
*/
circuit Foo {
f: u8;
y: (u8, u8);
@ -7,37 +13,33 @@ circuit Foo {
return 1u16;
}
}
function main() {
function main(k: bool) -> bool {
let x = 10u32;
x += 20;
console.assert(x == 30u32);
let w = 3u32;
w += x;
console.assert(w == 33u32);
let y = [1u8, 2u8, 3, 4];
y[0] += 3u8;
y[0..3][1] *= 3;
console.assert(y[0] == 4u8);
console.assert(y[1] == 6u8);
let z = (1u8, 2u8);
z.1 += 3u8;
console.assert(z.1 == 5u8);
let foo = Foo { f: 6u8, y: (1u8, 1u8) };
foo.f += 2u8;
console.assert(foo.f == 8u8);
let complex = 2u8;
complex += 22u8 - 2u8+ 1u8;
console.assert(complex == 23u8);
let a = [[0u8; 1]; 4];
a[2][0] += 1u8;
console.assert(a[2][0] == 1u8);
let b = [0u8; (4, 1)];
b[2][0] += 1u8;
console.assert(a[2][0] == 1u8);
return x == 30u32 && w == 33u32 && y[0] == 4u8 && y[1] == 6u8
&& z.1 == 5u8 && foo.f == 8u8 && a[2][0] == 1u8 && a[2][0] == 1u8
&& k;
}

View File

@ -0,0 +1,5 @@
[main]
k: bool = true;
[registers]
r0: bool = true;

View File

@ -0,0 +1,5 @@
[main]
s2: [char; 2] = "he";
[registers]
out: bool = true;

View File

@ -0,0 +1,14 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/two.in
*/
function main(s2: [char; 2]) -> bool {
let s = "\u{2764}ello, World!\u{DDDD}";
s[..2] = s2;
let x = "test1";
let z = [1u8, 2u8, 3u8, 4u8];
z[0.."test" == "test" ? 2 : 2] = [10u8, 10];
return z == [10u8, 10, 3, 4] && s == "hello, World!\u{DDDD}";
}

View File

@ -22,3 +22,6 @@ outputs:
a:
type: bool
value: "false"
initial_ast: 1b4069c1fe2f0b258116c5864b19dfb2205e3cd8e13ea79d78fcdb0e9c1a8d50
canonicalized_ast: 1b4069c1fe2f0b258116c5864b19dfb2205e3cd8e13ea79d78fcdb0e9c1a8d50
type_inferenced_ast: d2aefbdd9fd4c931d4ee60f1a435f3da0d827e7425d2fd0a9868de22cc11ed73

View File

@ -22,3 +22,6 @@ outputs:
a:
type: bool
value: "false"
initial_ast: 975c6893ed20b632a3dc9c39f7fe9f381e7dda4b17b6c1f05ff7480e3bf2ee9d
canonicalized_ast: 975c6893ed20b632a3dc9c39f7fe9f381e7dda4b17b6c1f05ff7480e3bf2ee9d
type_inferenced_ast: bbc3818f0267a746d6ab324ef9b9de489ca65cd1624f528dae941841f39517af

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- " --> compiler-test:7:24\n |\n 7 | const z: [u8; 2] = y[..1u32][..x];\n | ^^^^^^^^^^^^^^\n |\n = array index out of bounds: '0'"

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- " --> compiler-test:4:13\n |\n 4 | let a = [true; (0)];\n | ^^^^^^^^^^^\n |\n = received dimension size of 0, expected it to be 1 or larger."

View File

@ -16,3 +16,6 @@ outputs:
out:
type: bool
value: "true"
initial_ast: 9808de8c342c41e060d3d3134eb168c8d8cc3ff0641cb8d9779a1746b9fa1687
canonicalized_ast: 1479a9afd623ad11ca137555fd86a3f0a6da39641d5b2da712273242541c246e
type_inferenced_ast: 9bf998e088b9cce0f40a0326fa8e744c88d8168e04c563a2fbd6a57acd23da1f

View File

@ -22,3 +22,6 @@ outputs:
x:
type: bool
value: "false"
initial_ast: 25f4af112eb1512952d78bb7fa1d5287e3ab778255307f69304bbe1756575085
canonicalized_ast: 248b7cc7462c3f035f337c9232a08bb5a911d7f4e153dd804a32bc597adb0210
type_inferenced_ast: ebc3a5632c2d65e51cd9934b1ee4e395867808deeda3ecddfeaebb1b08093ed7

View File

@ -22,3 +22,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: b3bae883863f88babaafa80d4c029974767fba5fea89ac8c2ab10512e61a38ba
canonicalized_ast: 9070de3276acf8d06ac58439247130e444c9b02de25b968ad1fc746650a1896c
type_inferenced_ast: 40a38002031be2cf0141c9ea33562fe69fc3891baeba9c92c487915b97d82507

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: f5e4014d45239734a04d57c7b130fdf9752de245a4341062063aa5e818c5aa05
canonicalized_ast: 8c16a6b011fc067411acaa497386bc5df9b96b91ef739f4992ba416ecf98bafc
type_inferenced_ast: 17d810699ef381a0a9c4efcd2ad6da64b76ce5d629c05db7b2d07d563e077548

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: 25f4af112eb1512952d78bb7fa1d5287e3ab778255307f69304bbe1756575085
canonicalized_ast: 248b7cc7462c3f035f337c9232a08bb5a911d7f4e153dd804a32bc597adb0210
type_inferenced_ast: ebc3a5632c2d65e51cd9934b1ee4e395867808deeda3ecddfeaebb1b08093ed7

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 21f90ee0a01e1238101360b72909766a148155d853fd903a3031d66340915101
canonicalized_ast: cccb2040ce9b654f27e9a8e36976f220545c2888ed2aa9db73843b38407322f2
type_inferenced_ast: 7cee4f94edf86b6c61af5dbb389b8901c57292810abf4cd6b4855dfee40370c7

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 796cfe23085a2fd72700df353d266d3e2f62e893faeba8ed1af5ee5178f8e706
canonicalized_ast: d06970075b65456a138d9286fd3c445c928a55bf9819d98603b494c38563eae1
type_inferenced_ast: 41b1e49c972a34ed3d4629feabe3cb37f2078ba44fd1f3bee0a1888ca86f7ae4

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 3c24983a1b881bd00f5f0fd3a40b471a35f5252798f4ed81784b68693529ad59
canonicalized_ast: 177d06133dcc527a3110335158a888f4a0e5a5e904c2d6df57807563fd0ab386
type_inferenced_ast: 06e32299c26e20b9a25104686911ecd4e94123bd8a90e7890a244b6288678f27

View File

@ -22,3 +22,6 @@ outputs:
r:
type: "[u8; 3]"
value: "\"123\""
initial_ast: 81dd2c459d5a1bff4963fb2cfdc67348183061934025b96739dc05c7b65a2a8b
canonicalized_ast: 81dd2c459d5a1bff4963fb2cfdc67348183061934025b96739dc05c7b65a2a8b
type_inferenced_ast: fcb8de69c92dff4a4adb8a160fc3b78042f394cd0dc627c5bf06820a095d7012

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: ca5fc7bf19d8e6ee1b1421f1a37ea84c42bc89e8ac90711488bc17e996e88a91
canonicalized_ast: ca5fc7bf19d8e6ee1b1421f1a37ea84c42bc89e8ac90711488bc17e996e88a91
type_inferenced_ast: 2823901914ffea0d4cfcf449b9e45b46f67255e0b50f7a946b0552b240bedc0d

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: a588964cfb6989b22b8bf7d6feaf90d09e228d61b09a48fd4e5e4b44473b5bd0
canonicalized_ast: a588964cfb6989b22b8bf7d6feaf90d09e228d61b09a48fd4e5e4b44473b5bd0
type_inferenced_ast: 838744e4d681a06ccb685d0c0de65897234d64f0a49887e896fbda087f3edfd6

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: 2506cc8885eaae80a2ff90d1d231440dcfafd10fd8eb53317112ff2d2240d65e
canonicalized_ast: 2506cc8885eaae80a2ff90d1d231440dcfafd10fd8eb53317112ff2d2240d65e
type_inferenced_ast: bc0e1e40fcb7ac04e1dec943be5b93a1e39d43bee68a26713716765775674577

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: e238db049bc888e9243b421a188edbe5ae160127164b6bb75e54125052455565
canonicalized_ast: e238db049bc888e9243b421a188edbe5ae160127164b6bb75e54125052455565
type_inferenced_ast: e498240b5cb8c4d46a0b1035f208025df8e5feeabf9dddaa859a0a695ae8c5f6

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: d6195e7c9e70c521660ba312c607850110d864a1979004972a0f2908d476efd3
canonicalized_ast: a3483e0912a5d47c95775b1b2d2c62fa5acd5f3c0432757dc261475183156490
type_inferenced_ast: 54b0f61496c50ced01700f61d9c3eac6056d3835f38c2f39fe0c20e45447be63

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: 42d14deb7baaf81b59723a453b1aa09e68bfc8677ce2903596de69ad6b7677ab
canonicalized_ast: 42d14deb7baaf81b59723a453b1aa09e68bfc8677ce2903596de69ad6b7677ab
type_inferenced_ast: 1559a3a4db454285ab969d20276d9112fca0b24f6726f64d4b0371dccde32abf

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: c7cf923f9ca2a963279a8ff7ae9aa0a11eaddc8ba3e107d48f3aef1d1c55a50f
canonicalized_ast: c7cf923f9ca2a963279a8ff7ae9aa0a11eaddc8ba3e107d48f3aef1d1c55a50f
type_inferenced_ast: 58b19d80de0abea85877257b60305e1f7b9d2e67044f60d0159699131d4ba6ec

View File

@ -16,3 +16,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: dbc983cae35c2cd763e9bc4505a2d1e6c063fa62ccdc858a75644175512c1558
canonicalized_ast: dbc983cae35c2cd763e9bc4505a2d1e6c063fa62ccdc858a75644175512c1558
type_inferenced_ast: 42686f9d46c46c829259d4b68643d144d126e61a899e3c413ea09d0ed12d24d1

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 42a9307b4efda61137f9816a43e5c07a9d6b143bd88f609be7e549cb3b21d731
canonicalized_ast: 42a9307b4efda61137f9816a43e5c07a9d6b143bd88f609be7e549cb3b21d731
type_inferenced_ast: 67e643a53bb3efb99367869a1f3a937570f61658b004a4261e87b028f4976fad

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 073b0033613b8c2f8ca027d0486697b5503943dbc65cec9cbbc6b5665e7432e4
canonicalized_ast: 6751d75a95af032784678411bb4e0f59b509ec624daea475cab10b9cf14fe6a0
type_inferenced_ast: 9b9ac4ba4533ecae7ec74da2ab929cfa85be393391887e95ffadf4d1df3004be

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: d04220b24fd2648e859fab4caf69727b5532dbe1ee68db9d569153514e161a85
canonicalized_ast: 36d30f97ff15f08a4a88b384a362168014d56bc90d6a3837fd213b2acfc42357
type_inferenced_ast: 363bdf0ef5cf40b1b63a2cefa3d509ca731809568b7392899cbe73ec13104ecd

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 15fa7dd3949e323b759a7290ff433fb0f6ec83308b1b9b1a6bb129650191bc80
canonicalized_ast: 6a0262a7865ecf453b147449c52f23a1ffb38995c45d0a7c23a78255b9cbbb1b
type_inferenced_ast: 571acef2dd154ad80da051c43f402a9d10593c07b234de69fe9fc19284f09849

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: ec1e31c0b1e2cc2cfa1476b9189d1b3e95e786d5b55e4c350a6888860613f4b2
canonicalized_ast: dacc5bfe970669abcebe9363e0bc84fe7fb8e0c816dda756b00cc38ae993e781
type_inferenced_ast: f8c48aff4a11661fe164e69af32a99a5259f05a10287de26aea2fd323d4744ef

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: 37ec6089b9e1af0c552e259848d1ecd8bb361dd8a5c348d6b34f7f5262dc6f40
canonicalized_ast: ad2b199caadb797e02aded3020468c9d7a2b3094652c3b27436b8f98cc71dc05
type_inferenced_ast: cb373502d7141af431342592470482ef936a5fc9e6f4ede8a01e8e98537988de

View File

@ -16,3 +16,6 @@ outputs:
r0:
type: bool
value: "true"
initial_ast: b351c4655069ba4e5ae6759b10109406d64b74c652aab8be3547912df3e10c83
canonicalized_ast: e9e15873ef2727704b7b4f711516e6f8833a177fe4ff9379823dca293ecb8a72
type_inferenced_ast: d040a5aac628379fa32c3e36980f8dac3996a5240bc3482e44c2fdb1d8c3ef60

View File

@ -34,3 +34,6 @@ outputs:
x:
type: bool
value: "true"
initial_ast: 457931d2a45a5872b3f523ee9ed3ae922635750e38048927ee39dcd2fdaf338d
canonicalized_ast: 457931d2a45a5872b3f523ee9ed3ae922635750e38048927ee39dcd2fdaf338d
type_inferenced_ast: 5268ad28b10aedcd44c0aafced11ed0351999fceb6a202ed5a1faf833da5c2c4

Some files were not shown because too many files have changed in this diff Show More