mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 11:12:48 +03:00
pull latest master
This commit is contained in:
commit
3200a9cea1
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1230,6 +1230,7 @@ dependencies = [
|
||||
"pest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -47,6 +47,9 @@ version = "1.0"
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.thiserror]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3"
|
||||
|
||||
|
@ -21,7 +21,7 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
fn ast(ast: &Grammar) -> Ast {
|
||||
Ast::new("leo_tree", &ast)
|
||||
Ast::new("leo_tree", &ast).unwrap()
|
||||
}
|
||||
|
||||
fn bench_big_if_else(c: &mut Criterion) {
|
||||
|
@ -14,12 +14,14 @@
|
||||
// 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::{Circuit, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
|
||||
use crate::{Circuit, DeprecatedError, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
|
||||
use leo_grammar::{
|
||||
annotations::{Annotation, AnnotationArguments, AnnotationName},
|
||||
definitions::{AnnotatedDefinition, Definition},
|
||||
};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub fn load_annotation(
|
||||
@ -29,19 +31,37 @@ pub fn load_annotation(
|
||||
_functions: &mut IndexMap<Identifier, Function>,
|
||||
tests: &mut IndexMap<Identifier, TestFunction>,
|
||||
_expected: &mut Vec<FunctionInput>,
|
||||
) {
|
||||
) -> Result<(), DeprecatedError> {
|
||||
let ast_annotation = annotated_definition.annotation;
|
||||
let ast_definition = *annotated_definition.definition;
|
||||
|
||||
match ast_definition {
|
||||
Definition::Import(_) => unimplemented!("annotated imports are not supported yet"),
|
||||
Definition::Circuit(_) => unimplemented!("annotated circuits are not supported yet"),
|
||||
Definition::Function(_) => unimplemented!("annotated functions are not supported yet"),
|
||||
Definition::TestFunction(ast_test) => {
|
||||
let test = TestFunction::from(ast_test);
|
||||
load_annotated_test(test, ast_annotation, tests)
|
||||
Definition::Import(_) => {
|
||||
unimplemented!("annotated imports are not supported yet");
|
||||
}
|
||||
Definition::Circuit(_) => {
|
||||
unimplemented!("annotated circuits are not supported yet");
|
||||
}
|
||||
Definition::Function(function) => match ast_annotation.name {
|
||||
// If it's deprecated for more than one type of syntax,
|
||||
// we could just call it before the match on ast_definition.
|
||||
AnnotationName::Context(_) => Err(DeprecatedError::try_from(ast_annotation.name).unwrap()),
|
||||
AnnotationName::Test(_) => {
|
||||
let ident = Identifier::from(function.identifier.clone());
|
||||
_functions.remove(&ident);
|
||||
|
||||
let test_function = leo_grammar::functions::TestFunction::from(function);
|
||||
let test = TestFunction::from(test_function);
|
||||
tests.insert(ident, test.clone());
|
||||
|
||||
load_annotated_test(test, ast_annotation, tests);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Definition::Deprecated(_) => Ok(()),
|
||||
Definition::Annotated(_) => {
|
||||
unimplemented!("nested annotations are not supported yet");
|
||||
}
|
||||
Definition::Annotated(_) => unimplemented!("nested annotations are not supported yet"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +70,10 @@ pub fn load_annotated_test(test: TestFunction, annotation: Annotation, tests: &m
|
||||
let ast_arguments = annotation.arguments;
|
||||
|
||||
match name {
|
||||
AnnotationName::Context(_) => load_annotated_test_context(test, ast_arguments, tests),
|
||||
AnnotationName::Test(_) if ast_arguments.is_some() => {
|
||||
load_annotated_test_context(test, ast_arguments.unwrap(), tests)
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
63
ast/src/errors/deprecated.rs
Normal file
63
ast/src/errors/deprecated.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright (C) 2019-2020 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::{Error as FormattedError, Span};
|
||||
use leo_grammar::{annotations::AnnotationName, definitions::Deprecated};
|
||||
|
||||
use std::{convert::TryFrom, path::Path};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DeprecatedError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
}
|
||||
|
||||
impl DeprecatedError {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
DeprecatedError::Error(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_from_span(message: String, span: Span) -> Self {
|
||||
DeprecatedError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<Deprecated<'ast>> for DeprecatedError {
|
||||
fn from(deprecated: Deprecated<'ast>) -> Self {
|
||||
match deprecated {
|
||||
Deprecated::TestFunction(test_function) => DeprecatedError::new_from_span(
|
||||
"\"test function...\" is deprecated. Did you mean @test annotation?".to_string(),
|
||||
Span::from(test_function.span.clone()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> TryFrom<AnnotationName<'ast>> for DeprecatedError {
|
||||
type Error = bool;
|
||||
|
||||
fn try_from(annotation_name: AnnotationName<'ast>) -> Result<Self, bool> {
|
||||
match annotation_name {
|
||||
AnnotationName::Context(context) => Ok(DeprecatedError::new_from_span(
|
||||
"\"@context(...)\" is deprecated. Did you mean @test annotation?".to_string(),
|
||||
Span::from(context.span.clone()),
|
||||
)),
|
||||
_ => Err(false),
|
||||
}
|
||||
}
|
||||
}
|
@ -14,5 +14,30 @@
|
||||
// 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/>.
|
||||
|
||||
pub mod deprecated;
|
||||
pub use deprecated::*;
|
||||
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
use error::Error as FormattedError;
|
||||
|
||||
use leo_grammar::ParserError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AstError {
|
||||
#[error("{}", _0)]
|
||||
DeprecatedError(#[from] DeprecatedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ParserError(#[from] ParserError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
JsonError(#[from] serde_json::error::Error),
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
//! This module contains the [`Ast`] type, a wrapper around the [`Program`] type.
|
||||
//! The [`Ast`] type is intended to be parsed and modified by different passes
|
||||
//! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`Ast`].
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod annotation;
|
||||
pub use self::annotation::*;
|
||||
@ -74,10 +76,10 @@ pub struct Ast {
|
||||
|
||||
impl Ast {
|
||||
/// Creates a new ast from a given program name and grammar tree.
|
||||
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Self {
|
||||
Self {
|
||||
ast: Program::from(program_name, ast.as_repr()),
|
||||
}
|
||||
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Result<Self, AstError> {
|
||||
Ok(Self {
|
||||
ast: Program::from(program_name, ast.as_repr())?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner program ast representation.
|
||||
|
@ -14,11 +14,11 @@
|
||||
// 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 leo_ast::Ast;
|
||||
use leo_grammar::{Grammar, ParserError};
|
||||
use leo_ast::{Ast, AstError};
|
||||
use leo_grammar::Grammar;
|
||||
use std::{env, fs, path::Path};
|
||||
|
||||
fn to_leo_tree(filepath: &Path) -> Result<String, ParserError> {
|
||||
fn to_leo_tree(filepath: &Path) -> Result<String, AstError> {
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_filepath = filepath.to_path_buf();
|
||||
let program_string = Grammar::load_file(&program_filepath)?;
|
||||
@ -27,15 +27,14 @@ fn to_leo_tree(filepath: &Path) -> Result<String, ParserError> {
|
||||
let ast = Grammar::new(&program_filepath, &program_string)?;
|
||||
|
||||
// Parse the pest ast and constructs a ast.
|
||||
let leo_ast = Ast::new("leo_tree", &ast);
|
||||
let leo_ast = Ast::new("leo_tree", &ast)?;
|
||||
|
||||
// Serializes the tree into JSON format.
|
||||
let serialized_leo_ast = Ast::to_json_string(&leo_ast)?;
|
||||
|
||||
Ok(serialized_leo_ast)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), ParserError> {
|
||||
fn main() -> Result<(), AstError> {
|
||||
// Parse the command-line arguments as strings.
|
||||
let cli_arguments = env::args().collect::<Vec<String>>();
|
||||
|
||||
|
@ -17,7 +17,16 @@
|
||||
//! A Leo program consists of import, circuit, and function definitions.
|
||||
//! Each defined type consists of ast statements and expressions.
|
||||
|
||||
use crate::{load_annotation, Circuit, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
|
||||
use crate::{
|
||||
load_annotation,
|
||||
Circuit,
|
||||
DeprecatedError,
|
||||
Function,
|
||||
FunctionInput,
|
||||
Identifier,
|
||||
ImportStatement,
|
||||
TestFunction,
|
||||
};
|
||||
use leo_grammar::{definitions::Definition, files::File};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@ -37,7 +46,7 @@ const MAIN_FUNCTION_NAME: &str = "main";
|
||||
|
||||
impl<'ast> Program {
|
||||
//! Logic to convert from an abstract syntax tree (ast) representation to a Leo program.
|
||||
pub fn from(program_name: &str, program_ast: &File<'ast>) -> Self {
|
||||
pub fn from(program_name: &str, program_ast: &File<'ast>) -> Result<Self, DeprecatedError> {
|
||||
let mut imports = vec![];
|
||||
let mut circuits = IndexMap::new();
|
||||
let mut functions = IndexMap::new();
|
||||
@ -48,10 +57,15 @@ impl<'ast> Program {
|
||||
.definitions
|
||||
.to_owned()
|
||||
.into_iter()
|
||||
.for_each(|definition| match definition {
|
||||
Definition::Import(import) => imports.push(ImportStatement::from(import)),
|
||||
// Use of Infallible to say we never expect an Some(Ok(...))
|
||||
.find_map::<Result<std::convert::Infallible, _>, _>(|definition| match definition {
|
||||
Definition::Import(import) => {
|
||||
imports.push(ImportStatement::from(import));
|
||||
None
|
||||
}
|
||||
Definition::Circuit(circuit) => {
|
||||
circuits.insert(Identifier::from(circuit.identifier.clone()), Circuit::from(circuit));
|
||||
None
|
||||
}
|
||||
Definition::Function(function_def) => {
|
||||
let function = Function::from(function_def);
|
||||
@ -59,13 +73,13 @@ impl<'ast> Program {
|
||||
expected_input = function.input.clone();
|
||||
}
|
||||
functions.insert(function.identifier.clone(), function);
|
||||
None
|
||||
}
|
||||
Definition::TestFunction(test_def) => {
|
||||
let test = TestFunction::from(test_def);
|
||||
tests.insert(test.function.identifier.clone(), test);
|
||||
Definition::Deprecated(deprecated) => {
|
||||
Some(Err(DeprecatedError::from(deprecated)))
|
||||
}
|
||||
Definition::Annotated(annotated_definition) => {
|
||||
load_annotation(
|
||||
let loaded_annotation = load_annotation(
|
||||
annotated_definition,
|
||||
&mut imports,
|
||||
&mut circuits,
|
||||
@ -73,17 +87,23 @@ impl<'ast> Program {
|
||||
&mut tests,
|
||||
&mut expected_input,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
match loaded_annotation {
|
||||
Ok(_) => None,
|
||||
Err(deprecated_err) => Some(Err(deprecated_err))
|
||||
}
|
||||
}
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Ok(Self {
|
||||
name: program_name.to_string(),
|
||||
expected_input,
|
||||
imports,
|
||||
circuits,
|
||||
functions,
|
||||
tests,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
7
ast/tests/serialization/deprecated_error.leo
Normal file
7
ast/tests/serialization/deprecated_error.leo
Normal file
@ -0,0 +1,7 @@
|
||||
function main() {
|
||||
return 1 + 1
|
||||
}
|
||||
|
||||
test function old {
|
||||
console.log("old");
|
||||
}
|
@ -14,19 +14,19 @@
|
||||
// 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 leo_ast::Ast;
|
||||
#[cfg(not(feature = "ci_skip"))]
|
||||
use leo_ast::Program;
|
||||
use leo_grammar::Grammar;
|
||||
use leo_ast::{Ast, AstError};
|
||||
use leo_grammar::{Grammar, ParserError};
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn to_ast(program_filepath: &Path) -> Ast {
|
||||
fn to_ast(program_filepath: &Path) -> Result<Ast, AstError> {
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_string = Grammar::load_file(program_filepath).unwrap();
|
||||
let program_string = Grammar::load_file(program_filepath)?;
|
||||
|
||||
// Parses the Leo file and constructs a grammar ast.
|
||||
let ast = Grammar::new(&program_filepath, &program_string).unwrap();
|
||||
let ast = Grammar::new(&program_filepath, &program_string)?;
|
||||
|
||||
// Parses the pest ast and constructs a Leo ast.
|
||||
Ast::new("leo_tree", &ast)
|
||||
@ -40,7 +40,7 @@ fn test_serialize() {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_ast(&program_filepath)
|
||||
to_ast(&program_filepath).unwrap()
|
||||
};
|
||||
|
||||
// Serializes the ast into JSON format.
|
||||
@ -60,7 +60,7 @@ fn test_deserialize() {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_ast(&program_filepath)
|
||||
to_ast(&program_filepath).unwrap()
|
||||
};
|
||||
|
||||
// Construct an ast by deserializing a ast JSON file.
|
||||
@ -77,7 +77,7 @@ fn test_serialize_deserialize_serialize() {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_ast(&program_filepath)
|
||||
to_ast(&program_filepath).unwrap()
|
||||
};
|
||||
|
||||
// Serializes the ast into JSON format.
|
||||
@ -91,3 +91,29 @@ fn test_serialize_deserialize_serialize() {
|
||||
|
||||
assert_eq!(serialized_ast, reserialized_ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_read_error() {
|
||||
let error_result = {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/dne.leo");
|
||||
|
||||
to_ast(&program_filepath)
|
||||
}
|
||||
.map_err(|err| matches!(err, AstError::ParserError(x) if matches!(x, ParserError::FileReadError(_))));
|
||||
|
||||
assert!(error_result.err().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_parser_error() {
|
||||
let error_result = {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/parser_error.leo");
|
||||
|
||||
to_ast(&program_filepath)
|
||||
}
|
||||
.map_err(|err| matches!(err, AstError::ParserError(_)));
|
||||
|
||||
assert!(error_result.err().unwrap());
|
||||
}
|
||||
|
1
ast/tests/serialization/parser_error.leo
Normal file
1
ast/tests/serialization/parser_error.leo
Normal file
@ -0,0 +1 @@
|
||||
invalid
|
@ -184,7 +184,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
})?;
|
||||
|
||||
// Construct the core ast from the pest ast.
|
||||
let core_ast = Ast::new(&self.package_name, &pest_ast);
|
||||
let core_ast = Ast::new(&self.package_name, &pest_ast)?;
|
||||
|
||||
// Store the main program file.
|
||||
self.program = core_ast.into_repr();
|
||||
@ -241,7 +241,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
let package_name = &self.package_name;
|
||||
|
||||
// Construct the core ast from the pest ast.
|
||||
let core_ast = Ast::new(package_name, &ast);
|
||||
let core_ast = Ast::new(package_name, &ast)?;
|
||||
|
||||
// Store the main program file.
|
||||
self.program = core_ast.into_repr();
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError};
|
||||
use leo_ast::AstError;
|
||||
use leo_grammar::ParserError;
|
||||
use leo_imports::ImportParserError;
|
||||
use leo_input::InputParserError;
|
||||
@ -27,6 +28,9 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompilerError {
|
||||
#[error("{}", _0)]
|
||||
AstError(#[from] AstError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ImportError(#[from] ImportError),
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
test function fake_test() {}
|
||||
@test
|
||||
function fake_test() {}
|
||||
|
||||
function main() {}
|
||||
|
||||
|
@ -24,6 +24,7 @@ use serde::Serialize;
|
||||
#[pest_ast(rule(Rule::annotation_name))]
|
||||
pub enum AnnotationName<'ast> {
|
||||
Context(Context<'ast>),
|
||||
Test(Test<'ast>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
@ -33,3 +34,11 @@ pub struct Context<'ast> {
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::test))]
|
||||
pub struct Test<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use serde::Serialize;
|
||||
pub struct Annotation<'ast> {
|
||||
pub symbol: AnnotationSymbol<'ast>,
|
||||
pub name: AnnotationName<'ast>,
|
||||
pub arguments: AnnotationArguments<'ast>,
|
||||
pub arguments: Option<AnnotationArguments<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -17,8 +17,8 @@
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
circuits::Circuit,
|
||||
definitions::AnnotatedDefinition,
|
||||
functions::{Function, TestFunction},
|
||||
definitions::{AnnotatedDefinition, Deprecated},
|
||||
functions::Function,
|
||||
imports::Import,
|
||||
};
|
||||
|
||||
@ -32,5 +32,5 @@ pub enum Definition<'ast> {
|
||||
Import(Import<'ast>),
|
||||
Circuit(Circuit<'ast>),
|
||||
Function(Function<'ast>),
|
||||
TestFunction(TestFunction<'ast>),
|
||||
Deprecated(Deprecated<'ast>),
|
||||
}
|
||||
|
26
grammar/src/definitions/deprecated.rs
Normal file
26
grammar/src/definitions/deprecated.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2019-2020 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::{ast::Rule, functions::TestFunction};
|
||||
|
||||
use pest_ast::FromPest;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::deprecated))]
|
||||
pub enum Deprecated<'ast> {
|
||||
TestFunction(TestFunction<'ast>),
|
||||
}
|
@ -19,3 +19,6 @@ pub use annotated_definition::*;
|
||||
|
||||
pub mod definition;
|
||||
pub use definition::*;
|
||||
|
||||
pub mod deprecated;
|
||||
pub use deprecated::*;
|
||||
|
@ -27,6 +27,9 @@ pub enum ParserError {
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("{}", _0)]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("{}", _0)]
|
||||
JsonError(#[from] serde_json::error::Error),
|
||||
|
||||
@ -59,9 +62,3 @@ impl From<Error<Rule>> for ParserError {
|
||||
ParserError::SyntaxError(SyntaxError::from(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for ParserError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
ParserError::Crate("std::io", error.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -28,3 +28,10 @@ pub struct TestFunction<'ast> {
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> From<Function<'ast>> for TestFunction<'ast> {
|
||||
fn from(function: Function<'ast>) -> Self {
|
||||
let span = function.span.clone();
|
||||
TestFunction { function, span }
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,12 @@ definition = {
|
||||
| import
|
||||
| circuit
|
||||
| function
|
||||
| test_function
|
||||
| deprecated
|
||||
}
|
||||
|
||||
// Declared in definitions/deprecated.rs
|
||||
deprecated = {
|
||||
test_function
|
||||
}
|
||||
|
||||
// Declared in definitions/annotated_definition.rs
|
||||
@ -416,6 +421,9 @@ statement_definition = { declare ~ variables ~ "=" ~ expression ~ LINE_END}
|
||||
// Declared in statements/expression_statement.rs
|
||||
statement_expression = { expression ~ LINE_END }
|
||||
|
||||
// Decalred in functions/test_function.rs
|
||||
test_function = { "test" ~ function }
|
||||
|
||||
// Declared in statements/for_statement.rs
|
||||
statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ block }
|
||||
|
||||
@ -424,9 +432,6 @@ statement_return = { "return " ~ expression}
|
||||
|
||||
/// Functions
|
||||
|
||||
// Declared in functions/test_function.rs
|
||||
test_function = { "test " ~ function }
|
||||
|
||||
// Declared in functions/function.rs
|
||||
function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ block }
|
||||
|
||||
@ -520,18 +525,20 @@ formatted_container = { "{" ~ "}"}
|
||||
/// Annotations
|
||||
|
||||
// Declared in annotations/annotation.rs
|
||||
annotation = ${annotation_symbol ~ annotation_name ~ annotation_arguments}
|
||||
annotation = ${annotation_symbol ~ annotation_name ~ annotation_arguments? }
|
||||
|
||||
// Declared in annotations/annotation_symbol.rs
|
||||
annotation_symbol = ${"@"}
|
||||
|
||||
// Declared in annotations/annotation_name.rs
|
||||
annotation_name = {
|
||||
context
|
||||
context // deprecated
|
||||
| test
|
||||
}
|
||||
|
||||
// Declared in annotations/context.rs
|
||||
// Declared in annotations/annotation_name.rs
|
||||
context = {"context"}
|
||||
test = {"test"}
|
||||
|
||||
// Declared in annotations/annotation_argument.rs
|
||||
annotation_arguments = !{"(" ~ annotation_argument ~ ("," ~ annotation_argument)* ~ ","? ~ NEWLINE* ~ ")"}
|
||||
|
43
grammar/tests/annotated.rs
Normal file
43
grammar/tests/annotated.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2019-2020 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 leo_grammar::ast::{LanguageParser, Rule};
|
||||
|
||||
use pest::*;
|
||||
|
||||
#[test]
|
||||
fn test_annotation_no_context_test() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "@test",
|
||||
rule: Rule::annotation,
|
||||
tokens: [
|
||||
annotation(0, 5, [annotation_symbol(0, 1, []), annotation_name(1, 5, [test(1, 5, [])])])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_annotation_context_test() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "@test(custom)",
|
||||
rule: Rule::annotation,
|
||||
tokens: [
|
||||
annotation(0, 13, [annotation_symbol(0, 1, []), annotation_name(1, 5, [test(1, 5, [])]), annotation_arguments(5, 13, [annotation_argument(6, 12, [])])])
|
||||
]
|
||||
}
|
||||
}
|
56
grammar/tests/deprecated.rs
Normal file
56
grammar/tests/deprecated.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2019-2020 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 leo_grammar::ast::{LanguageParser, Rule};
|
||||
|
||||
use pest::*;
|
||||
|
||||
#[test]
|
||||
fn test_deprecated_test_function() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: r#"test function old() {
|
||||
return ()
|
||||
}"#,
|
||||
rule: Rule::deprecated,
|
||||
tokens: [
|
||||
deprecated(0, 37, [
|
||||
test_function(0, 37, [
|
||||
function(5, 37, [
|
||||
identifier(14, 17, []),
|
||||
block(20, 37, [
|
||||
statement(26, 36, [
|
||||
statement_return(26, 36, [expression(33, 36, [expression_term(33, 35, [expression_tuple(33, 35, [])])])])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deprecated_context_function() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "@context(custom)",
|
||||
rule: Rule::annotation,
|
||||
tokens: [
|
||||
annotation(0, 16, [annotation_symbol(0, 1, []), annotation_name(1, 8, [context(1, 8, [])]), annotation_arguments(8, 16, [annotation_argument(9, 15, [])])])
|
||||
]
|
||||
}
|
||||
}
|
@ -13,13 +13,16 @@
|
||||
|
||||
// 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 leo_ast::{Error as FormattedError, Identifier, Span};
|
||||
use leo_ast::{DeprecatedError, Error as FormattedError, Identifier, Span};
|
||||
use leo_grammar::ParserError;
|
||||
|
||||
use std::{io, path::Path};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ImportParserError {
|
||||
#[error("{}", _0)]
|
||||
DeprecatedError(#[from] DeprecatedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
|
@ -55,7 +55,7 @@ fn parse_import_file(package: &DirEntry, span: &Span) -> Result<Program, ImportP
|
||||
let ast = &Grammar::new(&file_path, &program_string)?;
|
||||
|
||||
// Build the package Leo syntax tree from the package abstract syntax tree.
|
||||
Ok(Program::from(&file_name, ast.as_repr()))
|
||||
Ok(Program::from(&file_name, ast.as_repr())?)
|
||||
}
|
||||
|
||||
impl ImportParser {
|
||||
|
@ -42,9 +42,12 @@ impl TestSymbolTable {
|
||||
let grammar = Grammar::new(&file_path, program_string).unwrap();
|
||||
|
||||
// Get Leo syntax tree.
|
||||
let ast = Ast::new(TEST_PROGRAM_PATH, &grammar);
|
||||
let ast_result = Ast::new(TEST_PROGRAM_PATH, &grammar);
|
||||
|
||||
Self { ast }
|
||||
// We always expect a valid ast for testing.
|
||||
Self {
|
||||
ast: ast_result.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -46,8 +46,10 @@ impl TestTypeInference {
|
||||
// Get parser syntax tree.
|
||||
let ast = Grammar::new(&file_path, program_string).unwrap();
|
||||
|
||||
let result = Ast::new(TEST_PROGRAM_NAME, &ast);
|
||||
// Get typed syntax tree.
|
||||
let typed = Ast::new(TEST_PROGRAM_NAME, &ast);
|
||||
// Always expect a valid SyntaxTree for testing.
|
||||
let typed = result.unwrap();
|
||||
let program = typed.into_repr();
|
||||
|
||||
// Create empty import parser.
|
||||
|
Loading…
Reference in New Issue
Block a user