Merge and resolve conflict on generated README.md.

(Since the file is generated, I've simply re-generated it to resolve the
conflict.)
This commit is contained in:
Alessandro Coglio 2021-04-28 21:57:34 -07:00
commit ccbf36e6ec
35 changed files with 1298 additions and 941 deletions

View File

@ -68,7 +68,7 @@ impl<'a> AsgContextInner<'a> {
#[allow(clippy::mut_from_ref)]
pub fn alloc_scope(&'a self, scope: Scope<'a>) -> &'a Scope<'a> {
match self.arena.alloc(ArenaNode::Scope(scope)) {
match self.arena.alloc(ArenaNode::Scope(Box::new(scope))) {
ArenaNode::Scope(e) => e,
_ => unimplemented!(),
}

View File

@ -44,7 +44,7 @@ pub(super) trait FromAst<'a, T: leo_ast::Node + 'static>: Sized {
pub enum ArenaNode<'a> {
Expression(Expression<'a>),
Scope(Scope<'a>),
Scope(Box<Scope<'a>>),
Statement(Statement<'a>),
Variable(Variable<'a>),
Circuit(Circuit<'a>),

View File

@ -24,7 +24,17 @@ pub use circuit::*;
mod function;
pub use function::*;
use crate::{ArenaNode, AsgContext, AsgConvertError, ImportResolver, Input, Scope};
use crate::{
node::FromAst,
ArenaNode,
AsgContext,
AsgConvertError,
DefinitionStatement,
ImportResolver,
Input,
Scope,
Statement,
};
use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span};
use indexmap::IndexMap;
@ -48,10 +58,12 @@ pub struct Program<'a> {
/// Maps function name => function code block.
pub functions: IndexMap<String, &'a Function<'a>>,
/// Maps global constant name => global const code block.
pub global_consts: IndexMap<String, &'a DefinitionStatement<'a>>,
/// Maps circuit name => circuit code block.
pub circuits: IndexMap<String, &'a Circuit<'a>>,
/// Bindings for names and additional program context.
pub scope: &'a Scope<'a>,
}
@ -168,6 +180,7 @@ impl<'a> Program<'a> {
let mut imported_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut imported_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut imported_global_consts: IndexMap<String, &'a DefinitionStatement<'a>> = IndexMap::new();
// Prepare locally relevant scope of imports.
for (package, symbol, span) in imported_symbols.into_iter() {
@ -180,12 +193,15 @@ impl<'a> Program<'a> {
ImportSymbol::All => {
imported_functions.extend(resolved_package.functions.clone().into_iter());
imported_circuits.extend(resolved_package.circuits.clone().into_iter());
imported_global_consts.extend(resolved_package.global_consts.clone().into_iter());
}
ImportSymbol::Direct(name) => {
if let Some(function) = resolved_package.functions.get(&name) {
imported_functions.insert(name.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(name.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(name.clone(), *global_const);
} else {
return Err(AsgConvertError::unresolved_import(
&*format!("{}.{}", pretty_package, name),
@ -198,6 +214,8 @@ impl<'a> Program<'a> {
imported_functions.insert(alias.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(alias.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(alias.clone(), *global_const);
} else {
return Err(AsgConvertError::unresolved_import(
&*format!("{}.{}", pretty_package, name),
@ -208,17 +226,18 @@ impl<'a> Program<'a> {
}
}
let import_scope = match context.arena.alloc(ArenaNode::Scope(Scope {
let import_scope = match context.arena.alloc(ArenaNode::Scope(Box::new(Scope {
context,
id: context.get_id(),
parent_scope: Cell::new(None),
circuit_self: Cell::new(None),
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(imported_functions),
global_consts: RefCell::new(imported_global_consts),
circuits: RefCell::new(imported_circuits),
function: Cell::new(None),
input: Cell::new(None),
})) {
}))) {
ArenaNode::Scope(c) => c,
_ => unimplemented!(),
};
@ -231,6 +250,7 @@ impl<'a> Program<'a> {
circuit_self: Cell::new(None),
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
global_consts: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
function: Cell::new(None),
});
@ -258,7 +278,29 @@ impl<'a> Program<'a> {
scope.functions.borrow_mut().insert(name.name.to_string(), function);
}
for (name, global_const) in program.global_consts.iter() {
global_const
.variable_names
.iter()
.for_each(|variable_name| assert!(name.contains(&variable_name.identifier.name.to_string())));
let gc = <&Statement<'a>>::from_ast(scope, global_const, None)?;
if let Statement::Definition(gc) = gc {
scope.global_consts.borrow_mut().insert(name.clone(), gc);
}
}
// Load concrete definitions.
let mut global_consts = IndexMap::new();
for (name, global_const) in program.global_consts.iter() {
global_const
.variable_names
.iter()
.for_each(|variable_name| assert!(name.contains(&variable_name.identifier.name.to_string())));
let asg_global_const = *scope.global_consts.borrow().get(name).unwrap();
global_consts.insert(name.clone(), asg_global_const);
}
let mut functions = IndexMap::new();
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
@ -290,6 +332,7 @@ impl<'a> Program<'a> {
id: context.get_id(),
name: program.name.clone(),
functions,
global_consts,
circuits,
imported_modules: resolved_packages
.into_iter()
@ -340,6 +383,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
let mut all_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut all_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut all_global_consts: IndexMap<String, &'a DefinitionStatement<'a>> = IndexMap::new();
let mut identifiers = InternalIdentifierGenerator { next: 0 };
for (_, program) in all_programs.into_iter() {
for (name, circuit) in program.circuits.iter() {
@ -356,6 +400,11 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
function.name.borrow_mut().name = identifier.clone().into();
all_functions.insert(identifier, *function);
}
for (name, global_const) in program.global_consts.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
all_global_consts.insert(identifier, *global_const);
}
}
leo_ast::Program {
@ -380,6 +429,20 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
.into_iter()
.map(|(_, circuit)| (circuit.name.borrow().clone(), circuit.into()))
.collect(),
global_consts: all_global_consts
.into_iter()
.map(|(_, global_const)| {
(
global_const
.variables
.iter()
.fold("".to_string(), |joined, variable_name| {
format!("{}, {}", joined, variable_name.borrow().name.name)
}),
global_const.into(),
)
})
.collect(),
}
}
@ -399,6 +462,21 @@ impl<'a> Into<leo_ast::Program> for &Program<'a> {
.iter()
.map(|(_, function)| (function.name.borrow().clone(), (*function).into()))
.collect(),
global_consts: self
.global_consts
.iter()
.map(|(_, global_const)| {
(
global_const
.variables
.iter()
.fold("".to_string(), |joined, variable_name| {
format!("{}, {}", joined, variable_name.borrow().name.name)
}),
(*global_const).into(),
)
})
.collect(),
}
}
}

View File

@ -322,6 +322,12 @@ impl<'a, R: ReconstructingReducerProgram<'a>> ReconstructingDirector<'a, R> {
self.reducer.reduce_circuit(input, members)
}
pub fn reduce_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> &'a DefinitionStatement<'a> {
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_global_const(input, value)
}
pub fn reduce_program(&mut self, input: Program<'a>) -> Program<'a> {
let imported_modules = input
.imported_modules
@ -339,7 +345,13 @@ impl<'a, R: ReconstructingReducerProgram<'a>> ReconstructingDirector<'a, R> {
.map(|(name, c)| (name.clone(), self.reduce_circuit(c)))
.collect();
let global_consts = input
.global_consts
.iter()
.map(|(name, gc)| (name.clone(), self.reduce_global_const(gc)))
.collect();
self.reducer
.reduce_program(input, imported_modules, functions, circuits)
.reduce_program(input, imported_modules, functions, circuits, global_consts)
}
}

View File

@ -383,12 +383,22 @@ pub trait ReconstructingReducerProgram<'a>: ReconstructingReducerStatement<'a> {
input
}
fn reduce_global_const(
&mut self,
input: &'a DefinitionStatement<'a>,
value: &'a Expression<'a>,
) -> &'a DefinitionStatement<'a> {
input.value.set(value);
input
}
fn reduce_program(
&mut self,
input: Program<'a>,
imported_modules: Vec<(String, Program<'a>)>,
functions: Vec<(String, &'a Function<'a>)>,
circuits: Vec<(String, &'a Circuit<'a>)>,
global_consts: Vec<(String, &'a DefinitionStatement<'a>)>,
) -> Program<'a> {
Program {
context: input.context,
@ -398,6 +408,7 @@ pub trait ReconstructingReducerProgram<'a>: ReconstructingReducerStatement<'a> {
functions: functions.into_iter().collect(),
circuits: circuits.into_iter().collect(),
scope: input.scope,
global_consts: global_consts.into_iter().collect(),
}
}
}

View File

@ -159,6 +159,10 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
Default::default()
}
fn visit_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_program(&mut self, input: &Program<'a>) -> VisitResult {
Default::default()
}

View File

@ -424,6 +424,16 @@ impl<'a, R: ProgramVisitor<'a>> VisitorDirector<'a, R> {
}
}
pub fn visit_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_global_const(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.value)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_program(&mut self, input: &Program<'a>) -> ConcreteVisitResult {
match self.visitor.visit_program(input) {
VisitResult::VisitChildren => {
@ -436,6 +446,9 @@ impl<'a, R: ProgramVisitor<'a>> VisitorDirector<'a, R> {
for (_, circuit) in input.circuits.iter() {
self.visit_circuit(circuit)?;
}
for (_, global_const) in input.global_consts.iter() {
self.visit_global_const(global_const)?;
}
Ok(())
}
x => x.into(),

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::{AsgContext, AsgConvertError, Circuit, Function, Input, Type, Variable};
use crate::{AsgContext, AsgConvertError, Circuit, DefinitionStatement, Function, Input, Type, Variable};
use indexmap::IndexMap;
use std::cell::{Cell, RefCell};
@ -42,6 +42,9 @@ pub struct Scope<'a> {
/// Maps function name => function.
pub functions: RefCell<IndexMap<String, &'a Function<'a>>>,
/// Maps global constant name => global const code block.
pub global_consts: RefCell<IndexMap<String, &'a DefinitionStatement<'a>>>,
/// Maps circuit name => circuit.
pub circuits: RefCell<IndexMap<String, &'a Circuit<'a>>>,
@ -161,6 +164,7 @@ impl<'a> Scope<'a> {
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
global_consts: RefCell::new(IndexMap::new()),
function: Cell::new(None),
input: Cell::new(None),
})

View File

@ -39,6 +39,22 @@ pub struct DefinitionStatement<'a> {
pub value: Cell<&'a Expression<'a>>,
}
impl<'a> DefinitionStatement<'a> {
pub fn split(&self) -> Vec<(String, Self)> {
self.variables
.iter()
.map(|variable| {
(variable.borrow().name.name.to_string(), DefinitionStatement {
parent: self.parent.clone(),
span: self.span.clone(),
variables: vec![variable],
value: self.value.clone(),
})
})
.collect()
}
}
impl<'a> Node for DefinitionStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()

View File

@ -17,7 +17,7 @@
//! A Leo program consists of import, circuit, and function definitions.
//! Each defined type consists of ast statements and expressions.
use crate::{Circuit, Function, FunctionInput, Identifier, ImportStatement};
use crate::{Circuit, DefinitionStatement, Function, FunctionInput, Identifier, ImportStatement};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
@ -30,6 +30,7 @@ pub struct Program {
pub expected_input: Vec<FunctionInput>,
pub imports: Vec<ImportStatement>,
pub circuits: IndexMap<Identifier, Circuit>,
pub global_consts: IndexMap<String, DefinitionStatement>,
pub functions: IndexMap<Identifier, Function>,
}
@ -66,6 +67,7 @@ impl Program {
expected_input: vec![],
imports: vec![],
circuits: IndexMap::new(),
global_consts: IndexMap::new(),
functions: IndexMap::new(),
}
}

View File

@ -450,8 +450,13 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
functions.insert(self.reduce_identifier(identifier)?, self.reduce_function(function)?);
}
let mut global_consts = IndexMap::new();
for (name, definition) in program.global_consts.iter() {
global_consts.insert(name.clone(), self.reduce_definition(&definition)?);
}
self.reducer
.reduce_program(program, inputs, imports, circuits, functions)
.reduce_program(program, inputs, imports, circuits, functions, global_consts)
}
pub fn reduce_function_input_variable(

View File

@ -398,6 +398,7 @@ pub trait ReconstructingReducer {
imports: Vec<ImportStatement>,
circuits: IndexMap<Identifier, Circuit>,
functions: IndexMap<Identifier, Function>,
global_consts: IndexMap<String, DefinitionStatement>,
) -> Result<Program, ReducerError> {
Ok(Program {
name: program.name.clone(),
@ -405,6 +406,7 @@ pub trait ReconstructingReducer {
imports,
circuits,
functions,
global_consts,
})
}

View File

@ -33,6 +33,10 @@ pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSy
) -> Result<OutputBytes, CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
for (_, global_const) in program.global_consts.iter() {
resolved_program.enforce_definition_statement(cs, global_const)?;
}
let main = {
let program = program;
program.functions.get("main").cloned()

View File

@ -24,7 +24,6 @@ use snarkvm_fields::PrimeField;
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn store_definition(&mut self, variable: &Variable, value: ConstrainedValue<'a, F, G>) {
let variable = variable.borrow();
self.store(variable.id, value);
}
}

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::errors::FunctionError;
use crate::errors::{ExpressionError, FunctionError, ImportError, StatementError};
use leo_asg::{AsgConvertError, FormattedError};
use leo_ast::{LeoError, ReducerError};
use leo_input::InputParserError;
@ -31,6 +31,12 @@ pub enum CompilerError {
#[error("{}", _0)]
AsgPassError(FormattedError),
#[error("{}", _0)]
ExpressionError(#[from] ExpressionError),
#[error("{}", _0)]
ImportError(#[from] ImportError),
#[error("{}", _0)]
InputParserError(#[from] InputParserError),
@ -57,6 +63,9 @@ pub enum CompilerError {
#[error("{}", _0)]
ReducerError(#[from] ReducerError),
#[error("{}", _0)]
StatementError(#[from] StatementError),
}
impl LeoError for CompilerError {}

View File

@ -26,6 +26,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn evaluate_ref(&mut self, variable_ref: &VariableRef) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
// Evaluate the identifier name in the current function scope
let variable = variable_ref.variable.borrow();
let result_value = if let Some(value) = self.get(variable.id) {
value.clone()
} else {

View File

@ -705,12 +705,19 @@ impl<R: ReconstructingReducer, O: CombinerOptions> CombineAstAsgDirector<R, O> {
functions.insert(ast_ident.clone(), self.reduce_function(ast_function, asg_function)?);
}
let mut global_consts = IndexMap::new();
for ((ast_str, ast_definition), (_asg_str, asg_definition)) in ast.global_consts.iter().zip(&asg.global_consts)
{
global_consts.insert(ast_str.clone(), self.reduce_definition(ast_definition, asg_definition)?);
}
self.ast_reducer.reduce_program(
ast,
ast.expected_input.clone(),
ast.imports.clone(),
circuits,
functions,
global_consts,
)
}

View File

@ -3,6 +3,7 @@
"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": [],

View File

@ -126,6 +126,7 @@
]
}
},
"global_consts": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],

View File

@ -2,6 +2,7 @@
"name": "",
"expected_input": [],
"imports": [],
"global_consts": {},
"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 {\\\"}\"}",

View File

@ -0,0 +1,46 @@
const basic: u32 = 8;
const array: [u8; (3, 2)] = [[0u8; 2]; 3];
const tuple = (1u32, 2u32);
const (a, b) = (1u32, 2u32);
const simple_group: group = 1group;
const complex_group = (_, 1)group;
const field_test: field = 2;
const use_another_const = basic + 1;
const foo = Foo { width: 10, height: 20 };
const uno = uno();
circuit Foo {
width: u32,
height: u32,
}
function uno() -> u32 {
return 1u32
}
function main() {
// basic test
console.assert(basic == 8u32);
// array test
console.assert(array[0][0] == 0);
console.assert(array[2][1] == 0);
// tuple test
let (x, y) = (1u32, 2u32);
console.assert(x == 1u32);
console.assert(y == 2u32);
// tuple extraction test
console.assert(a == 1u32);
console.assert(b == 2u32);
// group test
console.assert(simple_group == 1group);
console.assert(complex_group == (_, 1)group);
// field test
console.assert(field_test == 2field);
// use another const test
console.assert(use_another_const == 9u32);
// circuit test
console.assert(foo.width == 10u32);
console.assert(foo.height == 20u32);
// function test
console.assert(uno == 1u32);
}

View File

@ -0,0 +1,36 @@
// 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, expect_compiler_error, parse_program};
#[test]
fn test_global_consts() {
let program_string = include_str!("global_consts.leo");
let program = parse_program(program_string).unwrap();
assert_satisfied(program);
}
#[test]
fn test_modify_global_const() {
let program_string = include_str!("modify_global_const.leo");
let program = parse_program(program_string).unwrap();
assert!(parse_program(program_string).is_err());
}

View File

@ -0,0 +1,6 @@
const basic: u32 = 8;
function main() {
// Cannot re-assign!
basic = 2u32;
}

View File

@ -1,5 +1,7 @@
import test-import.foo as bar;
import bar.baz.ONE as UNO;
function main() {
console.assert(bar() == 1u32);
}
console.assert(UNO == 1u8);
}

View File

@ -4,4 +4,6 @@ circuit Baz {
circuit Bazzar {
a: u32
}
}
const ONE: u8 = 1;

View File

@ -5,7 +5,7 @@ import test-import.( // local import
import bar.( // imports directory import
Bar,
baz.(Baz, Bazzar),
baz.(Baz, Bazzar, ONE),
bat.bat.Bat,
);
@ -23,4 +23,5 @@ function main() {
const car = Car { c: 1u32 };
console.assert(car.c == 1u32);
console.assert(ONE == 1u8);
}

View File

@ -16,4 +16,5 @@ function main() {
const car = Car { c: 1u32 };
console.assert(car.c == 1u32);
console.assert(ONE == 1u8);
}

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ function two() -> u8 {
return 2u8;
}
const ONE = 1u8;
function main() {
const a = 1u8;
const b = 1field;

View File

@ -3,6 +3,7 @@
"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": [],

View File

@ -466,7 +466,7 @@ described above.
newline = line-feed / carriage-return / carriage-return line-feed
```
Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_;
Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_;
Line terminators form whitespace, along with spaces and horizontal tabs.
@ -476,7 +476,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs.
whitespace = space / horizontal-tab / newline
```
Go to: _[horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space), [newline](#user-content-newline)_;
Go to: _[horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline), [space](#user-content-space)_;
There are two kinds of comments in Leo, as in other languages.
@ -494,7 +494,7 @@ the ones used in the Java language reference.
comment = block-comment / end-of-line-comment
```
Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_;
Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_;
<a name="block-comment"></a>
@ -521,7 +521,7 @@ rest-of-block-comment-after-star = "/"
/ not-star-or-slash rest-of-block-comment
```
Go to: _[not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_;
Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_;
<a name="end-of-line-comment"></a>
@ -764,7 +764,7 @@ atomic-literal = untyped-literal
/ address-literal
```
Go to: _[unsigned-literal](#user-content-unsigned-literal), [address-literal](#user-content-address-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [signed-literal](#user-content-signed-literal), [product-group-literal](#user-content-product-group-literal)_;
Go to: _[signed-literal](#user-content-signed-literal), [untyped-literal](#user-content-untyped-literal), [field-literal](#user-content-field-literal), [product-group-literal](#user-content-product-group-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [unsigned-literal](#user-content-unsigned-literal)_;
After defining the (mostly) alphanumeric tokens above,
@ -809,7 +809,7 @@ token = keyword
/ symbol
```
Go to: _[annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol), [format-string](#user-content-format-string), [identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [atomic-literal](#user-content-atomic-literal)_;
Go to: _[keyword](#user-content-keyword), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol), [format-string](#user-content-format-string), [identifier](#user-content-identifier)_;
@ -845,7 +845,7 @@ signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128"
integer-type = unsigned-type / signed-type
```
Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_;
Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_;
The integer types, along with the field and group types,
@ -866,7 +866,7 @@ group-type = %s"group"
arithmetic-type = integer-type / field-type / group-type
```
Go to: _[field-type](#user-content-field-type), [integer-type](#user-content-integer-type), [group-type](#user-content-group-type)_;
Go to: _[integer-type](#user-content-integer-type), [field-type](#user-content-field-type), [group-type](#user-content-group-type)_;
The arithmetic types, along with the boolean and address types,
@ -887,7 +887,7 @@ address-type = %s"address"
scalar-type = boolean-type / arithmetic-type / address-type
```
Go to: _[arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_;
Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type)_;
Circuit types are denoted by identifiers and the keyword `Self`.
@ -927,7 +927,7 @@ or a tuple of one or more dimensions.
array-type = "[" type ";" array-dimensions "]"
```
Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_;
Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_;
<a name="array-dimensions"></a>
@ -948,7 +948,7 @@ i.e. types whose values contain (sub-)values
aggregate-type = tuple-type / array-type / circuit-type
```
Go to: _[circuit-type](#user-content-circuit-type), [array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type)_;
Go to: _[tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type)_;
Scalar and aggregate types form all the types.
@ -994,7 +994,7 @@ A literal is either an atomic one or an affine group literal.
literal = atomic-literal / affine-group-literal
```
Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_;
Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_;
The following rule is not directly referenced in the rules for expressions
@ -1036,7 +1036,7 @@ primary-expression = identifier
/ circuit-expression
```
Go to: _[tuple-expression](#user-content-tuple-expression), [circuit-expression](#user-content-circuit-expression), [array-expression](#user-content-array-expression), [expression](#user-content-expression), [literal](#user-content-literal), [identifier](#user-content-identifier)_;
Go to: _[expression](#user-content-expression), [tuple-expression](#user-content-tuple-expression), [array-expression](#user-content-array-expression), [literal](#user-content-literal), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier)_;
Tuple expressions construct tuples.
@ -1125,7 +1125,7 @@ circuit-construction = circuit-type "{"
"}"
```
Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_;
Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_;
<a name="circuit-inline-element"></a>
@ -1133,7 +1133,7 @@ Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#us
circuit-inline-element = identifier ":" expression / identifier
```
Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression)_;
Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier)_;
<a name="circuit-expression"></a>
@ -1184,7 +1184,7 @@ postfix-expression = primary-expression
/ postfix-expression "[" [expression] ".." [expression] "]"
```
Go to: _[function-arguments](#user-content-function-arguments), [identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [postfix-expression](#user-content-postfix-expression), [primary-expression](#user-content-primary-expression), [natural](#user-content-natural), [expression](#user-content-expression)_;
Go to: _[expression](#user-content-expression), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [postfix-expression](#user-content-postfix-expression), [natural](#user-content-natural)_;
Unary operators have the highest operator precedence.
@ -1198,7 +1198,7 @@ unary-expression = postfix-expression
/ "-" unary-expression
```
Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_;
Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_;
Next in the operator precedence is exponentiation,
@ -1212,7 +1212,7 @@ exponential-expression = unary-expression
/ unary-expression "**" exponential-expression
```
Go to: _[exponential-expression](#user-content-exponential-expression), [unary-expression](#user-content-unary-expression)_;
Go to: _[unary-expression](#user-content-unary-expression), [exponential-expression](#user-content-exponential-expression)_;
Next in precedence come multiplication and division, both left-associative.
@ -1224,7 +1224,7 @@ multiplicative-expression = exponential-expression
/ multiplicative-expression "/" exponential-expression
```
Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [exponential-expression](#user-content-exponential-expression)_;
Go to: _[exponential-expression](#user-content-exponential-expression), [multiplicative-expression](#user-content-multiplicative-expression)_;
Then there are addition and subtraction, both left-assocative.
@ -1286,7 +1286,7 @@ disjunctive-expression = conjunctive-expression
/ disjunctive-expression "||" conjunctive-expression
```
Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_;
Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_;
Finally we have conditional expressions.
@ -1323,7 +1323,8 @@ Blocks are possibly empty sequences of statements surrounded by curly braces.
```abnf
statement = expression-statement
/ return-statement
/ variable-definition-statement
/ variable-declaration
/ constant-declaration
/ conditional-statement
/ loop-statement
/ assignment-statement
@ -1331,7 +1332,7 @@ statement = expression-statement
/ block
```
Go to: _[expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [conditional-statement](#user-content-conditional-statement), [loop-statement](#user-content-loop-statement), [assignment-statement](#user-content-assignment-statement), [variable-definition-statement](#user-content-variable-definition-statement), [console-statement](#user-content-console-statement), [block](#user-content-block)_;
Go to: _[constant-declaration](#user-content-constant-declaration), [variable-declaration](#user-content-variable-declaration), [console-statement](#user-content-console-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [return-statement](#user-content-return-statement), [loop-statement](#user-content-loop-statement), [conditional-statement](#user-content-conditional-statement), [expression-statement](#user-content-expression-statement)_;
<a name="block"></a>
@ -1366,16 +1367,16 @@ The variables are either a single one or a tuple of two or more;
in all cases, there is just one optional type
and just one initializing expression.
<a name="variable-definition-statement"></a>
<a name="variable-declaration"></a>
```abnf
variable-definition-statement = ( %s"let" / %s"const" )
identifier-or-identifiers
[ ":" type ] "=" expression ";"
variable-declaration = %s"let" identifier-or-identifiers [ ":" type ] "=" expression ";"
constant-declaration = %s"const" identifier-or-identifiers [ ":" type ] "=" expression ";"
```
Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type), [expression](#user-content-expression)_;
<a name="identifier-or-identifiers"></a>
```abnf
identifier-or-identifiers = identifier
@ -1406,7 +1407,7 @@ conditional-statement = branch
/ branch %s"else" conditional-statement
```
Go to: _[branch](#user-content-branch), [block](#user-content-block), [conditional-statement](#user-content-conditional-statement)_;
Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_;
A loop statement implicitly defines a loop variable
@ -1418,7 +1419,7 @@ The body is a block.
loop-statement = %s"for" identifier %s"in" expression ".." expression block
```
Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [expression](#user-content-expression)_;
Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_;
An assignment statement is straightforward.
@ -1435,7 +1436,7 @@ assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**="
assignment-statement = expression assignment-operator expression ";"
```
Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_;
Go to: _[expression](#user-content-expression), [assignment-operator](#user-content-assignment-operator)_;
Console statements start with the `console` keyword,
@ -1521,7 +1522,7 @@ function-declaration = *annotation %s"function" identifier
block
```
Go to: _[type](#user-content-type), [block](#user-content-block), [function-parameters](#user-content-function-parameters), [identifier](#user-content-identifier)_;
Go to: _[block](#user-content-block), [type](#user-content-type), [identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters)_;
<a name="function-parameters"></a>
@ -1552,7 +1553,7 @@ Go to: _[function-input](#user-content-function-input)_;
function-input = [ %s"const" ] identifier ":" type
```
Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_;
A circuit member variable declaration consists of an identifier and a type.
@ -1621,7 +1622,7 @@ package-path = "*"
/ "(" package-path *( "," package-path ) [","] ")"
```
Go to: _[package-name](#user-content-package-name), [package-path](#user-content-package-path), [identifier](#user-content-identifier)_;
Go to: _[identifier](#user-content-identifier), [package-path](#user-content-package-path), [package-name](#user-content-package-name)_;
Finally, we define a file as a sequence of zero or more declarations.
@ -1631,9 +1632,10 @@ Finally, we define a file as a sequence of zero or more declarations.
declaration = import-declaration
/ function-declaration
/ circuit-declaration
/ constant-declaration
```
Go to: _[function-declaration](#user-content-function-declaration), [import-declaration](#user-content-import-declaration), [circuit-declaration](#user-content-circuit-declaration)_;
Go to: _[function-declaration](#user-content-function-declaration), [import-declaration](#user-content-import-declaration), [circuit-declaration](#user-content-circuit-declaration), [constant-declaration](#user-content-constant-declaration)_;
<a name="file"></a>

View File

@ -826,7 +826,8 @@ expression = conditional-expression
statement = expression-statement
/ return-statement
/ variable-definition-statement
/ variable-declaration
/ constant-declaration
/ conditional-statement
/ loop-statement
/ assignment-statement
@ -850,9 +851,9 @@ return-statement = %s"return" expression ";"
; in all cases, there is just one optional type
; and just one initializing expression.
variable-definition-statement = ( %s"let" / %s"const" )
identifier-or-identifiers
[ ":" type ] "=" expression ";"
variable-declaration = %s"let" identifier-or-identifiers [ ":" type ] "=" expression ";"
constant-declaration = %s"const" identifier-or-identifiers [ ":" type ] "=" expression ";"
identifier-or-identifiers = identifier
/ "(" identifier 1*( "," identifier ) ")"
@ -972,6 +973,7 @@ package-path = "*"
declaration = import-declaration
/ function-declaration
/ circuit-declaration
/ constant-declaration
file = *declaration

View File

@ -358,6 +358,23 @@ mod cli_tests {
assert!(run_cmd("leo clean", setup_path).is_ok());
}
#[test]
fn test_import() {
let dir = testdir("test");
let path = dir.path("test");
assert!(run_cmd("leo new import", &Some(path.clone())).is_ok());
let import_path = &Some(path.join("import"));
assert!(run_cmd("leo add no-package/definitely-no", import_path).is_err());
assert!(run_cmd("leo add justice-league/u8u32", import_path).is_ok());
assert!(run_cmd("leo remove u8u32", import_path).is_ok());
assert!(run_cmd("leo add --author justice-league --package u8u32", import_path).is_ok());
assert!(run_cmd("leo remove u8u32", import_path).is_ok());
assert!(run_cmd("leo remove u8u32", import_path).is_err());
}
#[test]
fn test_missing_file() {
let dir = testdir("test");

View File

@ -28,6 +28,7 @@ impl ParserContext {
let mut imports = Vec::new();
let mut circuits = IndexMap::new();
let mut functions = IndexMap::new();
let mut global_consts = IndexMap::new();
// let mut tests = IndexMap::new();
while self.has_next() {
@ -55,6 +56,10 @@ impl ParserContext {
// input_file: None,
// });
}
Token::Const => {
let (name, global_const) = self.parse_global_const_declaration()?;
global_consts.insert(name, global_const);
}
_ => {
return Err(SyntaxError::unexpected(
&token.token,
@ -76,6 +81,7 @@ impl ParserContext {
imports,
circuits,
functions,
global_consts,
})
}
@ -391,4 +397,20 @@ impl ParserContext {
block,
}))
}
///
/// Returns an [`(String, DefinitionStatement)`] AST node if the next tokens represent a global
/// const definition statement and assignment.
///
pub fn parse_global_const_declaration(&mut self) -> SyntaxResult<(String, DefinitionStatement)> {
let statement = self.parse_definition_statement()?;
let variable_names = statement
.variable_names
.iter()
.map(|variable_name| variable_name.identifier.name.to_string())
.collect::<Vec<String>>()
.join(",");
Ok((variable_names, statement))
}
}

View File

@ -3,6 +3,7 @@
"expected_input": [],
"imports": [],
"circuits": {},
"global_consts": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],