mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-25 18:42:26 +03:00
Resolve merge conflict
This commit is contained in:
commit
5375d97b40
3
.github/ISSUE_TEMPLATE.md
vendored
Normal file
3
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
## 👉 [Please follow one of these issue templates](https://github.com/AleoHQ/leo/issues/new/choose) 👈
|
||||
|
||||
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.
|
38
.github/ISSUE_TEMPLATE/01_bug_report.md
vendored
38
.github/ISSUE_TEMPLATE/01_bug_report.md
vendored
@ -1,38 +0,0 @@
|
||||
---
|
||||
name: "\U0001F41B Bug report"
|
||||
about: Create a bug report if something isn't working 🔧
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 🐛 Describe the Bug
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
<!-- To report a security issue, please email security@aleo.org. -->
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
#### Code snippet to reproduce
|
||||
|
||||
```rust
|
||||
# Add code here
|
||||
```
|
||||
|
||||
#### Stack trace & error message
|
||||
|
||||
```
|
||||
// Paste the output here
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
## System information
|
||||
|
||||
- <!-- Leo Version -->
|
||||
|
||||
- <!-- Rust Version -->
|
||||
|
||||
- <!-- Computer OS -->
|
34
.github/ISSUE_TEMPLATE/02_bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/02_bug_report.md
vendored
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: "\U0001F680 Feature request"
|
||||
about: Submit a new feature request 💡
|
||||
title: "[Feature]"
|
||||
labels: feature
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 🚀 Describe the Feature
|
||||
|
||||
<!-- A clear and concise description of the feature you are requesting -->
|
||||
|
||||
## Motivation
|
||||
|
||||
**Is the feature request related to a problem? If so, please describe.**
|
||||
|
||||
<!-- A clear and concise description of what the problem is.
|
||||
Please link to any relevant issues or other PRs! -->
|
||||
|
||||
**Is this something that currently cannot be done?**
|
||||
|
||||
## Solution
|
||||
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Are you willing to open a pull request?** (See [CONTRIBUTING](../../CONTRIBUTING.md))
|
||||
|
||||
## Alternative Solutions
|
||||
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
## Relevant Context
|
||||
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
52
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
52
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: Submit a bug report if something isn't working
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
---
|
||||
|
||||
## 🐛 Bug Report
|
||||
|
||||
<!--
|
||||
What's the bug in Leo that you found?
|
||||
How serious is this bug and what is affected?
|
||||
|
||||
To report a security issue in Leo, please email security@aleo.org.
|
||||
-->
|
||||
|
||||
(Write your description here)
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
<!--
|
||||
How do I reproduce this issue in Leo?
|
||||
Is there a code snippet I can use to reproduce the issue?
|
||||
Are there error messages or stack traces that would help debug this issue?
|
||||
-->
|
||||
|
||||
#### Code snippet to reproduce
|
||||
|
||||
```
|
||||
# Add code here
|
||||
```
|
||||
|
||||
#### Stack trace & error message
|
||||
|
||||
```
|
||||
// Paste the output here
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!--
|
||||
What was supposed to happen in Leo?
|
||||
What happened instead?
|
||||
-->
|
||||
|
||||
(Write what you expected to happen here)
|
||||
|
||||
## Your Environment
|
||||
|
||||
- <!-- Leo Version -->
|
||||
- <!-- Rust Version -->
|
||||
- <!-- Computer OS -->
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: ❓ Help and Support Discord Channel
|
||||
- name: ❓ Q&A Technical Support Channel
|
||||
url: https://discord.gg/dTw3wk9
|
||||
about: Please ask and answer questions here. 🏥
|
||||
about: For quick questions or technical troubleshooting, please ask them on our dedicated Discord channel.
|
||||
|
15
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: 📚 Documentation
|
||||
about: Report an issue related to documentation
|
||||
title: "[Docs]"
|
||||
labels: 'documentation'
|
||||
---
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
<!--
|
||||
Did you find a mistake in the Leo documentation?
|
||||
Is there documentation about Leo that's missing?
|
||||
-->
|
||||
|
||||
(Write your answer here.)
|
36
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
name: 🚀 Feature
|
||||
about: Submit a new feature request
|
||||
title: "[Feature]"
|
||||
labels: feature
|
||||
---
|
||||
|
||||
## 🚀 Feature
|
||||
|
||||
<!--
|
||||
What is the feature you would like to see in Leo?
|
||||
-->
|
||||
|
||||
(Write your description here)
|
||||
|
||||
## Motivation
|
||||
|
||||
<!--
|
||||
Why should this feature be implemented in Leo?
|
||||
How would this feature be used in Leo?
|
||||
|
||||
Is this feature request related to a problem? If so, please describe.
|
||||
Please link to any relevant issues or other PRs!
|
||||
-->
|
||||
|
||||
(Outline your motivation here)
|
||||
|
||||
## Implementation
|
||||
|
||||
<!--
|
||||
What needs to be built for the feature to be supported in Leo?
|
||||
What components of Leo will be affected by this design (if any)?
|
||||
How should this feature be implemented?
|
||||
-->
|
||||
|
||||
**Are you willing to open a pull request?** (See [CONTRIBUTING](../../CONTRIBUTING.md))
|
16
.github/ISSUE_TEMPLATE/proposal.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/proposal.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
name: 💥 Proposal
|
||||
about: Propose a non-trivial change to Leo
|
||||
title: "[Proposal]"
|
||||
labels: 'proposal'
|
||||
---
|
||||
|
||||
## 💥 Proposal
|
||||
|
||||
<!--
|
||||
What is your proposal for Leo?
|
||||
What are the implications of this proposal to Leo?
|
||||
Does your proposal affect other aspects of Aleo as well?
|
||||
-->
|
||||
|
||||
(Write your proposal here)
|
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<!--
|
||||
Thank you for submitting the PR! We appreciate you spending the time to work on these changes.
|
||||
|
||||
Help us understand your motivation by explaining why you decided to make this change.
|
||||
|
||||
Happy contributing!
|
||||
-->
|
||||
|
||||
## Motivation
|
||||
|
||||
(Write your motivation here)
|
||||
|
||||
## Test Plan
|
||||
|
||||
<!--
|
||||
If you changed any code,
|
||||
please provide us with clear instructions on how you verified your changes work.
|
||||
Bonus points for screenshots and videos!
|
||||
-->
|
||||
|
||||
(Write your test plan here)
|
||||
|
||||
## Related PRs
|
||||
|
||||
<!--
|
||||
If this PR adds or changes functionality,
|
||||
please take some time to update the docs at https://github.com/AleoHQ/leo,
|
||||
and link to your PR here.
|
||||
-->
|
||||
|
||||
(Link your related PRs here)
|
46
.github/workflows/ci.yml
vendored
46
.github/workflows/ci.yml
vendored
@ -42,8 +42,8 @@ jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
# env:
|
||||
# RUSTFLAGS: -Dwarnings
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
@ -68,27 +68,27 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
|
||||
- name: Check examples
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: check
|
||||
args: --examples --all
|
||||
|
||||
- name: Check examples with all features on stable
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --examples --all-features --all
|
||||
if: matrix.rust == 'stable'
|
||||
|
||||
- name: Check benchmarks on nightly
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all-features --examples --all --benches
|
||||
if: matrix.rust == 'nightly'
|
||||
# - name: Check examples
|
||||
# uses: actions-rs/cargo@v1
|
||||
# env:
|
||||
# CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
# with:
|
||||
# command: check
|
||||
# args: --examples --all
|
||||
#
|
||||
# - name: Check examples with all features on stable
|
||||
# uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: check
|
||||
# args: --examples --all-features --all
|
||||
# if: matrix.rust == 'stable'
|
||||
#
|
||||
# - name: Check benchmarks on nightly
|
||||
# uses: actions-rs/cargo@v1
|
||||
# with:
|
||||
# command: check
|
||||
# args: --all-features --examples --all --benches
|
||||
# if: matrix.rust == 'nightly'
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
|
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -649,6 +649,10 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leo-linter"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "leo-types"
|
||||
version = "0.1.0"
|
||||
@ -657,6 +661,7 @@ dependencies = [
|
||||
"leo-input",
|
||||
"pest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"snarkos-errors",
|
||||
"snarkos-models",
|
||||
]
|
||||
|
@ -13,7 +13,7 @@ name = "leo"
|
||||
path = "leo/main.rs"
|
||||
|
||||
[workspace]
|
||||
members = [ "ast", "compiler", "gadgets", "leo-input", "types" ]
|
||||
members = [ "ast", "compiler", "gadgets", "leo-input", "linter", "types" ]
|
||||
|
||||
[dependencies]
|
||||
leo-compiler = { path = "compiler", version = "0.1.0" }
|
||||
|
@ -18,3 +18,5 @@ pest_derive = { version = "2.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -29,29 +29,41 @@ pub(crate) use span::*;
|
||||
use from_pest::FromPest;
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
pub struct LeoParser;
|
||||
pub struct LeoAst<'ast> {
|
||||
ast: files::File<'ast>,
|
||||
}
|
||||
|
||||
impl LeoParser {
|
||||
impl<'ast> LeoAst<'ast> {
|
||||
/// Creates a new abstract syntax tree given the file path.
|
||||
pub fn new(file_path: &'ast PathBuf, program_string: &'ast str) -> Result<Self, ParserError> {
|
||||
// TODO (howardwu): Turn this check back on after fixing the testing module.
|
||||
// assert_eq!(program_string, fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?);
|
||||
|
||||
// Parse the file using leo.pest
|
||||
let file = &mut ast::parse(&program_string)
|
||||
.map_err(|error| ParserError::from(error.with_path(file_path.to_str().unwrap())))?;
|
||||
|
||||
// Builds the abstract syntax tree using pest derivation.
|
||||
let ast = files::File::<'ast>::from_pest(file).map_err(|_| ParserError::SyntaxTreeError)?;
|
||||
log::debug!("{:#?}", ast);
|
||||
|
||||
Ok(Self { ast })
|
||||
}
|
||||
|
||||
// TODO (howardwu): Remove this in favor of a dedicated file loader to verify checksums
|
||||
// and maintain a global cache of program strings during the compilation process.
|
||||
/// Loads the Leo code as a string from the given file path.
|
||||
pub fn load_file(file_path: &PathBuf) -> Result<String, ParserError> {
|
||||
pub fn load_file(file_path: &'ast PathBuf) -> Result<String, ParserError> {
|
||||
Ok(fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?)
|
||||
}
|
||||
|
||||
/// Parses the Leo program string and constructs an abstract syntax tree.
|
||||
pub fn parse_file<'a>(file_path: &'a PathBuf, program_string: &'a str) -> Result<files::File<'a>, ParserError> {
|
||||
// Parse the file using leo.pest
|
||||
let mut file = ast::parse(program_string)
|
||||
.map_err(|error| ParserError::from(error.with_path(file_path.to_str().unwrap())))?;
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let syntax_tree = files::File::from_pest(&mut file).map_err(|_| ParserError::SyntaxTreeError)?;
|
||||
log::debug!("{:#?}", syntax_tree);
|
||||
|
||||
Ok(syntax_tree)
|
||||
/// Returns a reference to the inner abstract syntax tree representation.
|
||||
pub fn as_repr(&self) -> &files::File<'ast> {
|
||||
&self.ast
|
||||
}
|
||||
|
||||
/// Serializes a given abstract syntax tree into a JSON string.
|
||||
pub fn to_json_string(syntax_tree: &files::File) -> Result<String, ParserError> {
|
||||
Ok(serde_json::to_string_pretty(syntax_tree)?)
|
||||
/// Serializes the abstract syntax tree into a JSON string.
|
||||
pub fn to_json_string(&self) -> Result<String, ParserError> {
|
||||
Ok(serde_json::to_string_pretty(&self.ast)?)
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
use leo_ast::{LeoParser, ParserError};
|
||||
use leo_ast::{LeoAst, ParserError};
|
||||
use std::{env, fs, path::Path};
|
||||
|
||||
fn to_leo_ast(filepath: &Path) -> Result<String, ParserError> {
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_filepath = filepath.to_path_buf();
|
||||
let program_string = LeoParser::load_file(&program_filepath)?;
|
||||
let program_string = LeoAst::load_file(&program_filepath)?;
|
||||
|
||||
// Parses the Leo program string and constructs an abstract syntax tree.
|
||||
let abstract_syntax_tree = LeoParser::parse_file(&program_filepath, &program_string)?;
|
||||
// Parses the Leo file and constructs an abstract syntax tree.
|
||||
let ast = LeoAst::new(&program_filepath, &program_string)?;
|
||||
|
||||
// Serializes the abstract syntax tree into JSON format.
|
||||
let serialized_ast = LeoParser::to_json_string(&abstract_syntax_tree)?;
|
||||
let serialized_ast = LeoAst::to_json_string(&ast)?;
|
||||
|
||||
Ok(serialized_ast)
|
||||
}
|
||||
|
1
ast/tests/mod.rs
Normal file
1
ast/tests/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod serialization;
|
91
ast/tests/serialization/expected_ast.json
Normal file
91
ast/tests/serialization/expected_ast.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"imports": [],
|
||||
"circuits": [],
|
||||
"functions": [
|
||||
{
|
||||
"function_name": {
|
||||
"value": "main",
|
||||
"span": {
|
||||
"input": "main",
|
||||
"start": 9,
|
||||
"end": 13
|
||||
}
|
||||
},
|
||||
"parameters": [],
|
||||
"returns": [],
|
||||
"statements": [
|
||||
{
|
||||
"Return": {
|
||||
"return_": {
|
||||
"Single": {
|
||||
"Binary": {
|
||||
"operation": "Add",
|
||||
"left": {
|
||||
"Value": {
|
||||
"Implicit": {
|
||||
"number": {
|
||||
"value": "1",
|
||||
"span": {
|
||||
"input": "1",
|
||||
"start": 29,
|
||||
"end": 30
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"input": "1",
|
||||
"start": 29,
|
||||
"end": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"Value": {
|
||||
"Implicit": {
|
||||
"number": {
|
||||
"value": "1",
|
||||
"span": {
|
||||
"input": "1",
|
||||
"start": 33,
|
||||
"end": 34
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"input": "1",
|
||||
"start": 33,
|
||||
"end": 34
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"input": "1 + 1",
|
||||
"start": 29,
|
||||
"end": 34
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"input": "return 1 + 1",
|
||||
"start": 22,
|
||||
"end": 34
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"input": "function main() {\n return 1 + 1\n}\n",
|
||||
"start": 0,
|
||||
"end": 37
|
||||
}
|
||||
}
|
||||
],
|
||||
"tests": [],
|
||||
"eoi": null,
|
||||
"span": {
|
||||
"input": "function main() {\n return 1 + 1\n}\n",
|
||||
"start": 0,
|
||||
"end": 37
|
||||
}
|
||||
}
|
22
ast/tests/serialization/json.rs
Normal file
22
ast/tests/serialization/json.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use leo_ast::LeoAst;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
let expected = include_str!("./expected_ast.json");
|
||||
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_string = LeoAst::load_file(&program_filepath).unwrap();
|
||||
|
||||
// Parses the Leo file and constructs an abstract syntax tree.
|
||||
let ast = LeoAst::new(&program_filepath, &program_string).unwrap();
|
||||
|
||||
// Serializes the abstract syntax tree into JSON format.
|
||||
let serialized_ast = LeoAst::to_json_string(&ast).unwrap();
|
||||
|
||||
assert_eq!(expected, serialized_ast);
|
||||
}
|
3
ast/tests/serialization/main.leo
Normal file
3
ast/tests/serialization/main.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
return 1 + 1
|
||||
}
|
1
ast/tests/serialization/mod.rs
Normal file
1
ast/tests/serialization/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod json;
|
@ -8,9 +8,9 @@ use crate::{
|
||||
OutputBytes,
|
||||
OutputFile,
|
||||
};
|
||||
use leo_ast::LeoParser;
|
||||
use leo_ast::LeoAst;
|
||||
use leo_input::LeoInputParser;
|
||||
use leo_types::{Input, MainInput, Program};
|
||||
use leo_types::{Input, LeoTypedAst, MainInput, Program};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
@ -47,6 +47,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the input and state files.
|
||||
/// Stores a typed ast of all input variables to the program.
|
||||
pub fn parse_input(&mut self, input_string: &str, state_string: &str) -> Result<(), CompilerError> {
|
||||
let input_syntax_tree = LeoInputParser::parse_file(&input_string)?;
|
||||
let state_syntax_tree = LeoInputParser::parse_file(&state_string)?;
|
||||
|
||||
self.program_input.parse_input(input_syntax_tree)?;
|
||||
self.program_input.parse_state(state_syntax_tree)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses program files.
|
||||
/// Returns a compiler struct that stores the typed program abstract syntax trees (ast).
|
||||
pub fn parse_program_without_input(
|
||||
@ -56,8 +68,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut compiler = Self::new(package_name, main_file_path, output_directory);
|
||||
|
||||
let program_string = compiler.load_program()?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_program()?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
@ -74,34 +85,33 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
let mut compiler = Self::new(package_name, main_file_path, output_directory);
|
||||
|
||||
compiler.parse_input(input_string, state_string)?;
|
||||
|
||||
let program_string = compiler.load_program()?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_program()?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
|
||||
/// Parse the input and state files.
|
||||
/// Stores a typed ast of all input variables to the program.
|
||||
pub fn parse_input(&mut self, input_string: &str, state_string: &str) -> Result<(), CompilerError> {
|
||||
let input_syntax_tree = LeoInputParser::parse_file(&input_string)?;
|
||||
let state_syntax_tree = LeoInputParser::parse_file(&state_string)?;
|
||||
/// Parses the Leo program file, constructs a syntax tree, and generates a program.
|
||||
pub(crate) fn parse_program(&mut self) -> Result<(), CompilerError> {
|
||||
// Use the parser to construct the abstract syntax tree.
|
||||
let program_string = LeoAst::load_file(&self.main_file_path)?;
|
||||
|
||||
self.program_input.parse_input(input_syntax_tree)?;
|
||||
self.program_input.parse_state(state_syntax_tree)?;
|
||||
|
||||
Ok(())
|
||||
self.parse_program_from_string(&program_string)
|
||||
}
|
||||
|
||||
/// Parse the program file and all associated import files.
|
||||
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
|
||||
// Parse the program syntax tree
|
||||
let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;
|
||||
/// Parses the Leo program string, constructs a syntax tree, and generates a program.
|
||||
/// Used for testing only.
|
||||
#[deprecated(note = "Please use the 'parse_program' method instead.")]
|
||||
pub fn parse_program_from_string(&mut self, program_string: &str) -> Result<(), CompilerError> {
|
||||
// Use the given bytes to construct the abstract syntax tree.
|
||||
let ast = LeoAst::new(&self.main_file_path, &program_string)?;
|
||||
|
||||
// Build program from syntax tree
|
||||
// Derive the package name.
|
||||
let package_name = self.package_name.clone();
|
||||
|
||||
self.program = Program::from(syntax_tree, package_name);
|
||||
// Use the typed parser to construct the typed syntax tree.
|
||||
let typed_tree = LeoTypedAst::new(&package_name, &ast);
|
||||
|
||||
self.program = typed_tree.into_repr();
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
|
||||
log::debug!("Program parsing complete\n{:#?}", self.program);
|
||||
@ -109,11 +119,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads the program file at `main_file_path`.
|
||||
fn load_program(&mut self) -> Result<String, CompilerError> {
|
||||
Ok(LeoParser::load_file(&self.main_file_path)?)
|
||||
}
|
||||
|
||||
/// Manually sets main function input
|
||||
pub fn set_main_input(&mut self, input: MainInput) {
|
||||
self.program_input.set_main_input(input);
|
||||
@ -158,7 +163,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
generate_constraints::<_, G, _>(cs, self.program, self.program_input, &self.imported_programs).map_err(
|
||||
|mut error| {
|
||||
error.set_path(path);
|
||||
|
||||
error
|
||||
},
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{errors::ImportError, ImportParser};
|
||||
use leo_ast::LeoParser;
|
||||
use leo_ast::LeoAst;
|
||||
use leo_types::{ImportSymbol, Program, Span};
|
||||
|
||||
use std::{ffi::OsString, fs::DirEntry, path::PathBuf};
|
||||
@ -30,12 +30,12 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result<Program, ImportErr
|
||||
}
|
||||
}
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let input_file = &LeoParser::load_file(&file_path)?;
|
||||
let syntax_tree = LeoParser::parse_file(&file_path, input_file)?;
|
||||
// Builds the abstract syntax tree.
|
||||
let program_string = &LeoAst::load_file(&file_path)?;
|
||||
let ast = &LeoAst::new(&file_path, &program_string)?;
|
||||
|
||||
// Generate aleo program from file
|
||||
Ok(Program::from(syntax_tree, file_name.clone()))
|
||||
// Generates the Leo program from file.
|
||||
Ok(Program::from(&file_name, ast.as_repr()))
|
||||
}
|
||||
|
||||
impl ImportParser {
|
||||
|
@ -45,7 +45,7 @@ pub(crate) fn parse_program(bytes: &[u8]) -> Result<EdwardsTestCompiler, Compile
|
||||
let mut compiler = new_compiler();
|
||||
let program_string = String::from_utf8_lossy(bytes);
|
||||
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_program_from_string(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
@ -90,8 +90,8 @@ pub fn parse_program_with_input(
|
||||
let program_string = String::from_utf8_lossy(program_bytes);
|
||||
let input_string = String::from_utf8_lossy(input_bytes);
|
||||
|
||||
compiler.parse_input(&input_string, EMPTY_FILE)?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_inputs(&inputs_string, EMPTY_FILE)?;
|
||||
compiler.parse_program_from_string(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
@ -105,8 +105,8 @@ pub fn parse_program_with_state(
|
||||
let program_string = String::from_utf8_lossy(program_bytes);
|
||||
let state_string = String::from_utf8_lossy(state_bytes);
|
||||
|
||||
compiler.parse_input(EMPTY_FILE, &state_string)?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_inputs(EMPTY_FILE, &state_string)?;
|
||||
compiler.parse_program_from_string(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
@ -122,8 +122,8 @@ pub fn parse_program_with_input_and_state(
|
||||
let input_string = String::from_utf8_lossy(input_bytes);
|
||||
let state_string = String::from_utf8_lossy(state_bytes);
|
||||
|
||||
compiler.parse_input(&input_string, &state_string)?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
compiler.parse_inputs(&inputs_string, &state_string)?;
|
||||
compiler.parse_program_from_string(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
|
56
leo/commands/lint.rs
Normal file
56
leo/commands/lint.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LintCommand;
|
||||
|
||||
impl CLI for LintCommand {
|
||||
type Options = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Lints the Leo files in the package (*)";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "lint";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let path = current_dir()?;
|
||||
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo lint`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ pub use self::deploy::*;
|
||||
pub mod init;
|
||||
pub use self::init::*;
|
||||
|
||||
pub mod lint;
|
||||
pub use self::lint::*;
|
||||
|
||||
pub mod load;
|
||||
pub use self::load::*;
|
||||
|
||||
|
18
leo/main.rs
18
leo/main.rs
@ -24,14 +24,15 @@ fn main() -> Result<(), CLIError> {
|
||||
InitCommand::new().display_order(1),
|
||||
BuildCommand::new().display_order(2),
|
||||
TestCommand::new().display_order(3),
|
||||
LoadCommand::new().display_order(4),
|
||||
UnloadCommand::new().display_order(5),
|
||||
SetupCommand::new().display_order(6),
|
||||
ProveCommand::new().display_order(7),
|
||||
RunCommand::new().display_order(8),
|
||||
PublishCommand::new().display_order(9),
|
||||
DeployCommand::new().display_order(10),
|
||||
CleanCommand::new().display_order(11),
|
||||
LintCommand::new().display_order(4),
|
||||
LoadCommand::new().display_order(5),
|
||||
UnloadCommand::new().display_order(6),
|
||||
SetupCommand::new().display_order(7),
|
||||
ProveCommand::new().display_order(8),
|
||||
RunCommand::new().display_order(9),
|
||||
PublishCommand::new().display_order(10),
|
||||
DeployCommand::new().display_order(11),
|
||||
CleanCommand::new().display_order(12),
|
||||
])
|
||||
.set_term_width(0)
|
||||
.get_matches();
|
||||
@ -41,6 +42,7 @@ fn main() -> Result<(), CLIError> {
|
||||
("init", Some(arguments)) => InitCommand::process(arguments),
|
||||
("build", Some(arguments)) => BuildCommand::process(arguments),
|
||||
("test", Some(arguments)) => TestCommand::process(arguments),
|
||||
("lint", Some(arguments)) => LintCommand::process(arguments),
|
||||
("load", Some(arguments)) => LoadCommand::process(arguments),
|
||||
("unload", Some(arguments)) => UnloadCommand::process(arguments),
|
||||
("setup", Some(arguments)) => SetupCommand::process(arguments),
|
||||
|
7
linter/Cargo.toml
Normal file
7
linter/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "leo-linter"
|
||||
version = "0.1.0"
|
||||
authors = ["The Aleo Team <hello@aleo.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
3
linter/src/main.rs
Normal file
3
linter/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
@ -4,6 +4,10 @@ version = "0.1.0"
|
||||
authors = ["The Aleo Team <hello@aleo.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[[bin]]
|
||||
name = "leo_types_ast"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
leo-ast = { path = "../ast", version = "0.1.0" }
|
||||
leo-input = { path = "../leo-input", version = "0.1.0" }
|
||||
@ -13,3 +17,4 @@ snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "
|
||||
|
||||
pest = { version = "2.0" }
|
||||
serde = { version = "1.0" }
|
||||
serde_json = { version = "1.0" }
|
||||
|
@ -2,11 +2,21 @@ use crate::Span;
|
||||
use leo_ast::common::Identifier as AstIdentifier;
|
||||
use leo_input::common::Identifier as InputAstIdentifier;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use serde::{
|
||||
de::{self, Visitor},
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
Serialize,
|
||||
Serializer,
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt};
|
||||
|
||||
/// An identifier in the constrained program.
|
||||
#[derive(Clone, Hash, Serialize, Deserialize)]
|
||||
///
|
||||
/// Attention - When adding or removing fields from this struct,
|
||||
/// please remember to update it's Serialize and Deserialize implementation
|
||||
/// to reflect the new struct instantiation.
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct Identifier {
|
||||
pub name: String,
|
||||
pub span: Span,
|
||||
@ -54,3 +64,61 @@ impl PartialEq for Identifier {
|
||||
}
|
||||
|
||||
impl Eq for Identifier {}
|
||||
|
||||
impl Serialize for Identifier {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
// Converts an element that implements Serialize into a string.
|
||||
fn to_json_string<E: Serialize, Error: serde::ser::Error>(element: &E) -> Result<String, Error> {
|
||||
serde_json::to_string(&element).map_err(|e| Error::custom(e.to_string()))
|
||||
}
|
||||
|
||||
// Load the struct elements into a BTreeMap (to preserve serialized ordering of keys).
|
||||
let mut key: BTreeMap<String, String> = BTreeMap::new();
|
||||
key.insert("name".to_string(), self.name.clone());
|
||||
key.insert("span".to_string(), to_json_string(&self.span)?);
|
||||
|
||||
// Convert the serialized object into a string for use as a key.
|
||||
serializer.serialize_str(&to_json_string(&key)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Identifier {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
struct IdentifierVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for IdentifierVisitor {
|
||||
type Value = Identifier;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a string encoding the typed Identifier struct")
|
||||
}
|
||||
|
||||
/// Implementation for recovering a string that serializes Identifier.
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
||||
// Converts a serialized string into an element that implements Deserialize.
|
||||
fn to_json_string<'a, D: Deserialize<'a>, Error: serde::de::Error>(
|
||||
serialized: &'a str,
|
||||
) -> Result<D, Error> {
|
||||
serde_json::from_str::<'a>(serialized).map_err(|e| Error::custom(e.to_string()))
|
||||
}
|
||||
|
||||
// Convert the serialized string into a BTreeMap to recover Identifier.
|
||||
let key: BTreeMap<String, String> = to_json_string(value)?;
|
||||
|
||||
let name = match key.get("name") {
|
||||
Some(name) => name.clone(),
|
||||
None => return Err(E::custom("missing 'name' in serialized Identifier struct")),
|
||||
};
|
||||
|
||||
let span: Span = match key.get("span") {
|
||||
Some(span) => to_json_string(span)?,
|
||||
None => return Err(E::custom("missing 'span' in serialized Identifier struct")),
|
||||
};
|
||||
|
||||
Ok(Identifier { name, span })
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(IdentifierVisitor)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use leo_ast::imports::Import as AstImport;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Import {
|
||||
pub package: Package,
|
||||
pub span: Span,
|
||||
|
@ -4,7 +4,7 @@ use leo_ast::imports::ImportSymbol as AstImportSymbol;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImportSymbol {
|
||||
pub symbol: Identifier,
|
||||
pub alias: Option<Identifier>,
|
||||
@ -31,7 +31,7 @@ impl fmt::Display for ImportSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
// todo: remove this
|
||||
// TODO (collin): remove this
|
||||
impl fmt::Debug for ImportSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.alias.is_some() {
|
||||
|
@ -4,7 +4,7 @@ use leo_ast::imports::Package as AstPackage;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Package {
|
||||
pub name: Identifier,
|
||||
pub access: PackageAccess,
|
||||
|
@ -4,7 +4,7 @@ use leo_ast::imports::PackageAccess as AstPackageAccess;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PackageAccess {
|
||||
Star(Span),
|
||||
SubPackage(Box<Package>),
|
||||
|
@ -1,3 +1,6 @@
|
||||
//! A typed syntax tree is represented as a `Program` and consists of import, circuit, and function definitions.
|
||||
//! Each defined type consists of typed statements and expressions.
|
||||
|
||||
pub mod circuits;
|
||||
pub use self::circuits::*;
|
||||
|
||||
@ -30,3 +33,37 @@ pub use self::statements::*;
|
||||
|
||||
pub mod types;
|
||||
pub use self::types::*;
|
||||
|
||||
use leo_ast::LeoAst;
|
||||
|
||||
use serde_json;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct LeoTypedAst {
|
||||
typed_ast: Program,
|
||||
}
|
||||
|
||||
impl LeoTypedAst {
|
||||
/// Creates a new typed syntax tree from a given program name and abstract syntax tree.
|
||||
pub fn new<'ast>(program_name: &str, ast: &LeoAst<'ast>) -> Self {
|
||||
Self {
|
||||
typed_ast: Program::from(program_name, ast.as_repr()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner typed syntax tree representation.
|
||||
pub fn into_repr(self) -> Program {
|
||||
self.typed_ast
|
||||
}
|
||||
|
||||
/// Serializes the typed syntax tree into a JSON string.
|
||||
pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
|
||||
Ok(serde_json::to_string_pretty(&self.typed_ast)?)
|
||||
}
|
||||
|
||||
/// Deserializes the JSON string into a typed syntax tree.
|
||||
pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> {
|
||||
let typed_ast: Program = serde_json::from_str(json)?;
|
||||
Ok(Self { typed_ast })
|
||||
}
|
||||
}
|
||||
|
56
types/src/main.rs
Normal file
56
types/src/main.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use leo_ast::{LeoAst, ParserError};
|
||||
use leo_types::LeoTypedAst;
|
||||
use std::{env, fs, path::Path};
|
||||
|
||||
fn to_leo_types_tree(filepath: &Path) -> Result<String, ParserError> {
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_filepath = filepath.to_path_buf();
|
||||
let program_string = LeoAst::load_file(&program_filepath)?;
|
||||
|
||||
// Parses the Leo file and constructs an abstract syntax tree.
|
||||
let ast = LeoAst::new(&program_filepath, &program_string)?;
|
||||
|
||||
// Parse the abstract syntax tree and constructs a typed syntax tree.
|
||||
let typed_ast = LeoTypedAst::new("leo_types_tree", &ast);
|
||||
|
||||
// Serializes the typed syntax tree into JSON format.
|
||||
let serialized_typed_tree = LeoTypedAst::to_json_string(&typed_ast)?;
|
||||
|
||||
Ok(serialized_typed_tree)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), ParserError> {
|
||||
// Parse the command-line arguments as strings.
|
||||
let cli_arguments = env::args().collect::<Vec<String>>();
|
||||
|
||||
// Check that the correct number of command-line arguments were passed in.
|
||||
if cli_arguments.len() < 2 || cli_arguments.len() > 3 {
|
||||
eprintln!("Warning - an invalid number of command-line arguments were provided.");
|
||||
println!(
|
||||
"\nCommand-line usage:\n\n\tleo_types_ast {{PATH/TO/INPUT_FILENAME}}.leo {{PATH/TO/OUTPUT_DIRECTORY (optional)}}\n"
|
||||
);
|
||||
return Ok(()); // Exit innocently
|
||||
}
|
||||
|
||||
// Construct the input filepath.
|
||||
let input_filepath = Path::new(&cli_arguments[1]);
|
||||
|
||||
// Construct the serialized typed syntax tree.
|
||||
let serialized_typed_tree = to_leo_types_tree(&input_filepath)?;
|
||||
println!("{}", serialized_typed_tree);
|
||||
|
||||
// Determine the output directory.
|
||||
let output_directory = match cli_arguments.len() == 3 {
|
||||
true => format!(
|
||||
"{}/{}.json",
|
||||
cli_arguments[2],
|
||||
input_filepath.file_stem().unwrap().to_str().unwrap()
|
||||
),
|
||||
false => format!("./{}.json", input_filepath.file_stem().unwrap().to_str().unwrap()),
|
||||
};
|
||||
|
||||
// Write the serialized abstract syntax tree to the output directory.
|
||||
fs::write(Path::new(&output_directory), serialized_typed_tree)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A simple program with statement expressions, program arguments and program returns.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Program {
|
||||
pub name: String,
|
||||
pub expected_input: Vec<InputVariable>,
|
||||
@ -22,10 +22,11 @@ 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(file: File<'ast>, name: String) -> Self {
|
||||
pub fn from(program_name: &str, program_ast: &File<'ast>) -> Self {
|
||||
// Compiled ast -> aleo program representation
|
||||
let imports = file
|
||||
let imports = program_ast
|
||||
.imports
|
||||
.to_owned()
|
||||
.into_iter()
|
||||
.map(|import| Import::from(import))
|
||||
.collect::<Vec<Import>>();
|
||||
@ -35,23 +36,23 @@ impl<'ast> Program {
|
||||
let mut tests = HashMap::new();
|
||||
let mut expected_input = vec![];
|
||||
|
||||
file.circuits.into_iter().for_each(|circuit| {
|
||||
program_ast.circuits.to_owned().into_iter().for_each(|circuit| {
|
||||
circuits.insert(Identifier::from(circuit.identifier.clone()), Circuit::from(circuit));
|
||||
});
|
||||
file.functions.into_iter().for_each(|function_def| {
|
||||
program_ast.functions.to_owned().into_iter().for_each(|function_def| {
|
||||
let function = Function::from(function_def);
|
||||
if function.function_name.name.eq(MAIN_FUNCTION_NAME) {
|
||||
expected_input = function.input.clone();
|
||||
}
|
||||
functions.insert(function.function_name.clone(), function);
|
||||
});
|
||||
file.tests.into_iter().for_each(|test_def| {
|
||||
program_ast.tests.to_owned().into_iter().for_each(|test_def| {
|
||||
let test = TestFunction::from(test_def);
|
||||
tests.insert(test.0.function_name.clone(), test);
|
||||
});
|
||||
|
||||
Self {
|
||||
name,
|
||||
name: program_name.to_string(),
|
||||
expected_input,
|
||||
imports,
|
||||
circuits,
|
||||
|
1
types/tests/mod.rs
Normal file
1
types/tests/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod serialization;
|
66
types/tests/serialization/expected_typed_ast.json
Normal file
66
types/tests/serialization/expected_typed_ast.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "leo_types_tree",
|
||||
"expected_inputs": [],
|
||||
"imports": [],
|
||||
"circuits": {},
|
||||
"functions": {
|
||||
"{\"name\":\"main\",\"span\":\"{\\\"text\\\":\\\" function main() {\\\",\\\"line\\\":1,\\\"start\\\":10,\\\"end\\\":14}\"}": {
|
||||
"function_name": "{\"name\":\"main\",\"span\":\"{\\\"text\\\":\\\" function main() {\\\",\\\"line\\\":1,\\\"start\\\":10,\\\"end\\\":14}\"}",
|
||||
"inputs": [],
|
||||
"returns": [],
|
||||
"statements": [
|
||||
{
|
||||
"Return": [
|
||||
[
|
||||
{
|
||||
"Add": [
|
||||
{
|
||||
"Implicit": [
|
||||
"1",
|
||||
{
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 12,
|
||||
"end": 13
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Implicit": [
|
||||
"1",
|
||||
{
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 16,
|
||||
"end": 17
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 12,
|
||||
"end": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
{
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 5,
|
||||
"end": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"text": " function main() {",
|
||||
"line": 1,
|
||||
"start": 1,
|
||||
"end": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"tests": {}
|
||||
}
|
76
types/tests/serialization/json.rs
Normal file
76
types/tests/serialization/json.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use leo_ast::LeoAst;
|
||||
use leo_types::LeoTypedAst;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn to_typed_ast(program_filepath: &PathBuf) -> LeoTypedAst {
|
||||
// Loads the Leo code as a string from the given file path.
|
||||
let program_string = LeoAst::load_file(program_filepath).unwrap();
|
||||
|
||||
// Parses the Leo file and constructs an abstract syntax tree.
|
||||
let ast = LeoAst::new(&program_filepath, &program_string).unwrap();
|
||||
|
||||
// Parse the abstract syntax tree and constructs a typed syntax tree.
|
||||
let typed_ast = LeoTypedAst::new("leo_types_tree", &ast);
|
||||
|
||||
typed_ast
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
// Construct a typed syntax tree from the given test file.
|
||||
let typed_ast = {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_typed_ast(&program_filepath)
|
||||
};
|
||||
|
||||
// Serializes the typed syntax tree into JSON format.
|
||||
let serialized_typed_ast = typed_ast.to_json_string().unwrap();
|
||||
|
||||
// Load the expected typed syntax tree.
|
||||
let expected = include_str!("expected_typed_ast.json");
|
||||
|
||||
println!("{}", serialized_typed_ast);
|
||||
assert_eq!(expected, serialized_typed_ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() {
|
||||
// Load the expected typed syntax tree.
|
||||
let expected_typed_ast = {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_typed_ast(&program_filepath)
|
||||
};
|
||||
|
||||
// Construct a typed syntax tree by deserializing a typed syntax tree JSON file.
|
||||
let serialized_typed_ast = include_str!("expected_typed_ast.json");
|
||||
let typed_ast = LeoTypedAst::from_json_string(serialized_typed_ast).unwrap();
|
||||
|
||||
assert_eq!(expected_typed_ast, typed_ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_deserialize_serialize() {
|
||||
// Construct a typed syntax tree from the given test file.
|
||||
let typed_ast = {
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
to_typed_ast(&program_filepath)
|
||||
};
|
||||
|
||||
// Serializes the typed syntax tree into JSON format.
|
||||
let serialized_typed_ast = typed_ast.to_json_string().unwrap();
|
||||
|
||||
// Deserializes the typed syntax tree into a LeoTypedAst.
|
||||
let typed_ast = LeoTypedAst::from_json_string(&serialized_typed_ast).unwrap();
|
||||
|
||||
// Reserializes the typed syntax tree into JSON format.
|
||||
let reserialized_typed_ast = typed_ast.to_json_string().unwrap();
|
||||
|
||||
assert_eq!(serialized_typed_ast, reserialized_typed_ast);
|
||||
}
|
3
types/tests/serialization/main.leo
Normal file
3
types/tests/serialization/main.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
return 1 + 1
|
||||
}
|
1
types/tests/serialization/mod.rs
Normal file
1
types/tests/serialization/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod json;
|
Loading…
Reference in New Issue
Block a user