mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-28 09:02:58 +03:00
Merge branch 'master' of github.com:AleoHQ/leo into fix/state-module-names
This commit is contained in:
commit
83f7c49d08
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -1312,6 +1312,8 @@ dependencies = [
|
|||||||
"leo-input",
|
"leo-input",
|
||||||
"leo-package",
|
"leo-package",
|
||||||
"leo-state",
|
"leo-state",
|
||||||
|
"leo-symbol-table",
|
||||||
|
"leo-type-inference",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"pest",
|
"pest",
|
||||||
"rand",
|
"rand",
|
||||||
@ -1481,6 +1483,31 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leo-symbol-table"
|
||||||
|
version = "1.0.4"
|
||||||
|
dependencies = [
|
||||||
|
"leo-ast",
|
||||||
|
"leo-core",
|
||||||
|
"leo-grammar",
|
||||||
|
"leo-imports",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leo-type-inference"
|
||||||
|
version = "1.0.4"
|
||||||
|
dependencies = [
|
||||||
|
"leo-ast",
|
||||||
|
"leo-grammar",
|
||||||
|
"leo-imports",
|
||||||
|
"leo-symbol-table",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.80"
|
version = "0.2.80"
|
||||||
|
@ -36,8 +36,8 @@ members = [
|
|||||||
"linter",
|
"linter",
|
||||||
"package",
|
"package",
|
||||||
"state",
|
"state",
|
||||||
# "symbol-table",
|
"symbol-table",
|
||||||
# "type-inference",
|
"type-inference",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies.leo-ast]
|
[dependencies.leo-ast]
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use leo_ast::LeoAst;
|
use leo_ast::Ast;
|
||||||
use leo_grammar::Grammar;
|
use leo_grammar::Grammar;
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use std::{path::Path, time::Duration};
|
use std::{path::Path, time::Duration};
|
||||||
|
|
||||||
fn leo_ast<'ast>(ast: &Grammar<'ast>) -> LeoAst {
|
fn ast<'ast>(ast: &Grammar<'ast>) -> Ast {
|
||||||
LeoAst::new("leo_tree", &ast)
|
Ast::new("leo_tree", &ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_big_if_else(c: &mut Criterion) {
|
fn bench_big_if_else(c: &mut Criterion) {
|
||||||
@ -29,7 +29,7 @@ fn bench_big_if_else(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./big_if_else.leo");
|
let program_string = include_str!("./big_if_else.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::big_if_else", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::big_if_else", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_big_ternary(c: &mut Criterion) {
|
fn bench_big_ternary(c: &mut Criterion) {
|
||||||
@ -37,7 +37,7 @@ fn bench_big_ternary(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./big_ternary.leo");
|
let program_string = include_str!("./big_ternary.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::big_ternary", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::big_ternary", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_big_circuit(c: &mut Criterion) {
|
fn bench_big_circuit(c: &mut Criterion) {
|
||||||
@ -45,7 +45,7 @@ fn bench_big_circuit(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./big_circuit.leo");
|
let program_string = include_str!("./big_circuit.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::big_circuit", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::big_circuit", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_long_expr(c: &mut Criterion) {
|
fn bench_long_expr(c: &mut Criterion) {
|
||||||
@ -53,7 +53,7 @@ fn bench_long_expr(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./long_expr.leo");
|
let program_string = include_str!("./long_expr.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::long_expr", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::long_expr", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_long_array(c: &mut Criterion) {
|
fn bench_long_array(c: &mut Criterion) {
|
||||||
@ -61,7 +61,7 @@ fn bench_long_array(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./long_array.leo");
|
let program_string = include_str!("./long_array.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::long_array", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::long_array", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_many_foos(c: &mut Criterion) {
|
fn bench_many_foos(c: &mut Criterion) {
|
||||||
@ -69,7 +69,7 @@ fn bench_many_foos(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./many_foos.leo");
|
let program_string = include_str!("./many_foos.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::many_foos", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::many_foos", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_many_assigns(c: &mut Criterion) {
|
fn bench_many_assigns(c: &mut Criterion) {
|
||||||
@ -77,7 +77,7 @@ fn bench_many_assigns(c: &mut Criterion) {
|
|||||||
let program_string = include_str!("./many_assigns.leo");
|
let program_string = include_str!("./many_assigns.leo");
|
||||||
let ast = Grammar::new(&filepath, program_string).unwrap();
|
let ast = Grammar::new(&filepath, program_string).unwrap();
|
||||||
|
|
||||||
c.bench_function("LeoAst::many_assigns", |b| b.iter(|| leo_ast(&ast)));
|
c.bench_function("Ast::many_assigns", |b| b.iter(|| ast(&ast)));
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(
|
||||||
|
@ -70,7 +70,7 @@ impl ArrayDimensions {
|
|||||||
/// Returns `true` if there is an array dimension equal to zero.
|
/// Returns `true` if there is an array dimension equal to zero.
|
||||||
///
|
///
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(&self) -> bool {
|
||||||
self.0.iter().find(|number| number.is_zero()).is_some()
|
self.0.iter().any(|number| number.is_zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
//! The abstract syntax tree (ast) for a Leo program.
|
//! The abstract syntax tree (ast) for a Leo program.
|
||||||
//!
|
//!
|
||||||
//! This module contains the [`LeoAst`] type, a wrapper around the [`Program`] type.
|
//! This module contains the [`Ast`] type, a wrapper around the [`Program`] type.
|
||||||
//! The [`LeoAst`] type is intended to be parsed and modified by different passes
|
//! 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 [`LeoAst`].
|
//! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`Ast`].
|
||||||
|
|
||||||
pub mod annotation;
|
pub mod annotation;
|
||||||
pub use self::annotation::*;
|
pub use self::annotation::*;
|
||||||
@ -63,34 +63,34 @@ use leo_grammar::Grammar;
|
|||||||
|
|
||||||
/// The abstract syntax tree (ast) for a Leo program.
|
/// The abstract syntax tree (ast) for a Leo program.
|
||||||
///
|
///
|
||||||
/// The [`LeoAst`] type represents a Leo program as a series of recursive data types.
|
/// The [`Ast`] type represents a Leo program as a series of recursive data types.
|
||||||
/// These data types form a tree that begins from a [`Program`] type root.
|
/// These data types form a tree that begins from a [`Program`] type root.
|
||||||
///
|
///
|
||||||
/// A new [`LeoAst`] can be created from a [`Grammar`] generated by the pest parser in the `grammar` module.
|
/// A new [`Ast`] can be created from a [`Grammar`] generated by the pest parser in the `grammar` module.
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct LeoAst {
|
pub struct Ast {
|
||||||
ast: Program,
|
ast: Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LeoAst {
|
impl Ast {
|
||||||
/// Creates a new syntax tree from a given program name and abstract syntax tree.
|
/// Creates a new ast from a given program name and grammar tree.
|
||||||
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Self {
|
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ast: Program::from(program_name, ast.as_repr()),
|
ast: Program::from(program_name, ast.as_repr()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the inner program syntax tree representation.
|
/// Returns a reference to the inner program ast representation.
|
||||||
pub fn into_repr(self) -> Program {
|
pub fn into_repr(self) -> Program {
|
||||||
self.ast
|
self.ast
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the syntax tree into a JSON string.
|
/// Serializes the ast into a JSON string.
|
||||||
pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
|
pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
|
||||||
Ok(serde_json::to_string_pretty(&self.ast)?)
|
Ok(serde_json::to_string_pretty(&self.ast)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserializes the JSON string into a syntax tree.
|
/// Deserializes the JSON string into a ast.
|
||||||
pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> {
|
pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> {
|
||||||
let ast: Program = serde_json::from_str(json)?;
|
let ast: Program = serde_json::from_str(json)?;
|
||||||
Ok(Self { ast })
|
Ok(Self { ast })
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use leo_ast::LeoAst;
|
use leo_ast::Ast;
|
||||||
use leo_grammar::{Grammar, ParserError};
|
use leo_grammar::{Grammar, ParserError};
|
||||||
use std::{env, fs, path::Path};
|
use std::{env, fs, path::Path};
|
||||||
|
|
||||||
@ -27,10 +27,10 @@ fn to_leo_tree(filepath: &Path) -> Result<String, ParserError> {
|
|||||||
let ast = Grammar::new(&program_filepath, &program_string)?;
|
let ast = Grammar::new(&program_filepath, &program_string)?;
|
||||||
|
|
||||||
// Parse the pest ast and constructs a ast.
|
// Parse the pest ast and constructs a ast.
|
||||||
let leo_ast = LeoAst::new("leo_tree", &ast);
|
let leo_ast = Ast::new("leo_tree", &ast);
|
||||||
|
|
||||||
// Serializes the tree into JSON format.
|
// Serializes the tree into JSON format.
|
||||||
let serialized_leo_ast = LeoAst::to_json_string(&leo_ast)?;
|
let serialized_leo_ast = Ast::to_json_string(&leo_ast)?;
|
||||||
|
|
||||||
Ok(serialized_leo_ast)
|
Ok(serialized_leo_ast)
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use leo_ast::LeoAst;
|
use leo_ast::Ast;
|
||||||
#[cfg(not(feature = "ci_skip"))]
|
#[cfg(not(feature = "ci_skip"))]
|
||||||
use leo_ast::Program;
|
use leo_ast::Program;
|
||||||
use leo_grammar::Grammar;
|
use leo_grammar::Grammar;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
fn to_ast(program_filepath: &Path) -> LeoAst {
|
fn to_ast(program_filepath: &Path) -> Ast {
|
||||||
// Loads the Leo code as a string from the given file path.
|
// 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).unwrap();
|
||||||
|
|
||||||
@ -29,14 +29,14 @@ fn to_ast(program_filepath: &Path) -> LeoAst {
|
|||||||
let ast = Grammar::new(&program_filepath, &program_string).unwrap();
|
let ast = Grammar::new(&program_filepath, &program_string).unwrap();
|
||||||
|
|
||||||
// Parses the pest ast and constructs a Leo ast.
|
// Parses the pest ast and constructs a Leo ast.
|
||||||
LeoAst::new("leo_tree", &ast)
|
Ast::new("leo_tree", &ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "ci_skip"))]
|
#[cfg(not(feature = "ci_skip"))]
|
||||||
fn test_serialize() {
|
fn test_serialize() {
|
||||||
// Construct a ast from the given test file.
|
// Construct an ast from the given test file.
|
||||||
let leo_ast = {
|
let ast = {
|
||||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
program_filepath.push("tests/serialization/main.leo");
|
program_filepath.push("tests/serialization/main.leo");
|
||||||
|
|
||||||
@ -44,20 +44,19 @@ fn test_serialize() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Serializes the ast into JSON format.
|
// Serializes the ast into JSON format.
|
||||||
let serialized_leo_ast: Program =
|
let serialized_ast: Program = serde_json::from_value(serde_json::to_value(ast.into_repr()).unwrap()).unwrap();
|
||||||
serde_json::from_value(serde_json::to_value(leo_ast.into_repr()).unwrap()).unwrap();
|
|
||||||
|
|
||||||
// Load the expected ast.
|
// Load the expected ast.
|
||||||
let expected: Program = serde_json::from_str(include_str!("expected_leo_ast.json")).unwrap();
|
let expected: Program = serde_json::from_str(include_str!("expected_leo_ast.json")).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected, serialized_leo_ast);
|
assert_eq!(expected, serialized_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "ci_skip"))]
|
#[cfg(not(feature = "ci_skip"))]
|
||||||
fn test_deserialize() {
|
fn test_deserialize() {
|
||||||
// Load the expected ast.
|
// Load the expected ast.
|
||||||
let expected_leo_ast = {
|
let expected_ast = {
|
||||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
program_filepath.push("tests/serialization/main.leo");
|
program_filepath.push("tests/serialization/main.leo");
|
||||||
|
|
||||||
@ -66,15 +65,15 @@ fn test_deserialize() {
|
|||||||
|
|
||||||
// Construct an ast by deserializing a ast JSON file.
|
// Construct an ast by deserializing a ast JSON file.
|
||||||
let serialized_ast = include_str!("expected_leo_ast.json");
|
let serialized_ast = include_str!("expected_leo_ast.json");
|
||||||
let leo_ast = LeoAst::from_json_string(serialized_ast).unwrap();
|
let ast = Ast::from_json_string(serialized_ast).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_leo_ast, leo_ast);
|
assert_eq!(expected_ast, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_deserialize_serialize() {
|
fn test_serialize_deserialize_serialize() {
|
||||||
// Construct a ast from the given test file.
|
// Construct an ast from the given test file.
|
||||||
let leo_ast = {
|
let ast = {
|
||||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
program_filepath.push("tests/serialization/main.leo");
|
program_filepath.push("tests/serialization/main.leo");
|
||||||
|
|
||||||
@ -82,13 +81,13 @@ fn test_serialize_deserialize_serialize() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Serializes the ast into JSON format.
|
// Serializes the ast into JSON format.
|
||||||
let serialized_leo_ast = leo_ast.to_json_string().unwrap();
|
let serialized_ast = ast.to_json_string().unwrap();
|
||||||
|
|
||||||
// Deserializes the serialized ast into a LeoAst.
|
// Deserializes the serialized ast into an ast.
|
||||||
let leo_ast = LeoAst::from_json_string(&serialized_leo_ast).unwrap();
|
let ast = Ast::from_json_string(&serialized_ast).unwrap();
|
||||||
|
|
||||||
// Reserializes the ast into JSON format.
|
// Reserializes the ast into JSON format.
|
||||||
let reserialized_leo_ast = leo_ast.to_json_string().unwrap();
|
let reserialized_ast = ast.to_json_string().unwrap();
|
||||||
|
|
||||||
assert_eq!(serialized_leo_ast, reserialized_leo_ast);
|
assert_eq!(serialized_ast, reserialized_ast);
|
||||||
}
|
}
|
||||||
|
@ -49,13 +49,13 @@ version = "1.0.4"
|
|||||||
path = "../state"
|
path = "../state"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
||||||
#[dependencies.leo-symbol-table]
|
[dependencies.leo-symbol-table]
|
||||||
#path = "../symbol-table"
|
path = "../symbol-table"
|
||||||
#version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
||||||
#[dependencies.leo-type-inference]
|
[dependencies.leo-type-inference]
|
||||||
#path = "../type-inference"
|
path = "../type-inference"
|
||||||
#version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
||||||
[dependencies.snarkos-curves]
|
[dependencies.snarkos-curves]
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -23,14 +23,14 @@ use crate::{
|
|||||||
OutputBytes,
|
OutputBytes,
|
||||||
OutputFile,
|
OutputFile,
|
||||||
};
|
};
|
||||||
use leo_ast::{Input, LeoAst, MainInput, Program};
|
use leo_ast::{Ast, Input, MainInput, Program};
|
||||||
use leo_grammar::Grammar;
|
use leo_grammar::Grammar;
|
||||||
use leo_imports::ImportParser;
|
use leo_imports::ImportParser;
|
||||||
use leo_input::LeoInputParser;
|
use leo_input::LeoInputParser;
|
||||||
use leo_package::inputs::InputPairs;
|
use leo_package::inputs::InputPairs;
|
||||||
use leo_state::verify_local_data_commitment;
|
use leo_state::verify_local_data_commitment;
|
||||||
// use leo_symbol_table::SymbolTable;
|
use leo_symbol_table::SymbolTable;
|
||||||
// use leo_type_inference::TypeInference;
|
use leo_type_inference::TypeInference;
|
||||||
|
|
||||||
use snarkos_dpc::{base_dpc::instantiated::Components, SystemParameters};
|
use snarkos_dpc::{base_dpc::instantiated::Components, SystemParameters};
|
||||||
use snarkos_errors::gadgets::SynthesisError;
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
@ -184,7 +184,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Construct the core ast from the pest ast.
|
// Construct the core ast from the pest ast.
|
||||||
let core_ast = LeoAst::new(&self.package_name, &pest_ast);
|
let core_ast = Ast::new(&self.package_name, &pest_ast);
|
||||||
|
|
||||||
// Store the main program file.
|
// Store the main program file.
|
||||||
self.program = core_ast.into_repr();
|
self.program = core_ast.into_repr();
|
||||||
@ -205,20 +205,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
/// catching type mismatch errors.
|
/// catching type mismatch errors.
|
||||||
///
|
///
|
||||||
pub(crate) fn check_program(&self) -> Result<(), CompilerError> {
|
pub(crate) fn check_program(&self) -> Result<(), CompilerError> {
|
||||||
// // Create a new symbol table from the program, imported_programs, and program_input.
|
// Create a new symbol table from the program, imported_programs, and program_input.
|
||||||
// let _symbol_table =
|
let symbol_table =
|
||||||
// SymbolTable::new(&self.program, &self.imported_programs, &self.program_input).map_err(|mut e| {
|
SymbolTable::new(&self.program, &self.imported_programs, &self.program_input).map_err(|mut e| {
|
||||||
// e.set_path(&self.main_file_path);
|
e.set_path(&self.main_file_path);
|
||||||
//
|
|
||||||
// e
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// // Run type inference check on program.
|
e
|
||||||
// TypeInference::new(&self.program, symbol_table).map_err(|mut e| {
|
})?;
|
||||||
// e.set_path(&self.main_file_path);
|
|
||||||
//
|
// Run type inference check on program.
|
||||||
// e
|
TypeInference::new(&self.program, symbol_table).map_err(|mut e| {
|
||||||
// })?;
|
e.set_path(&self.main_file_path);
|
||||||
|
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
|
||||||
tracing::debug!("Program checks complete");
|
tracing::debug!("Program checks complete");
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
let package_name = &self.package_name;
|
let package_name = &self.package_name;
|
||||||
|
|
||||||
// Construct the core ast from the pest ast.
|
// Construct the core ast from the pest ast.
|
||||||
let core_ast = LeoAst::new(package_name, &ast);
|
let core_ast = Ast::new(package_name, &ast);
|
||||||
|
|
||||||
// Store the main program file.
|
// Store the main program file.
|
||||||
self.program = core_ast.into_repr();
|
self.program = core_ast.into_repr();
|
||||||
@ -252,11 +252,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
// Parse and store all programs imported by the main program file.
|
// Parse and store all programs imported by the main program file.
|
||||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||||
|
|
||||||
// // Create a new symbol table from the program, imported programs, and program input.
|
// Create a new symbol table from the program, imported programs, and program input.
|
||||||
// let _symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?;
|
let symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?;
|
||||||
|
|
||||||
// // Run type inference check on program.
|
// Run type inference check on program.
|
||||||
// TypeInference::new(&self.program, symbol_table)?;
|
TypeInference::new(&self.program, symbol_table)?;
|
||||||
|
|
||||||
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
|||||||
let program_name = program.get_name();
|
let program_name = program.get_name();
|
||||||
let main_function_name = new_scope(&program_name, "main");
|
let main_function_name = new_scope(&program_name, "main");
|
||||||
|
|
||||||
resolved_program.store_definitions(program, imported_programs)?;
|
resolved_program.store_definitions(&program, imported_programs)?;
|
||||||
|
|
||||||
let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?;
|
let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?;
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
|||||||
let tests = program.tests.clone();
|
let tests = program.tests.clone();
|
||||||
|
|
||||||
// Store definitions
|
// Store definitions
|
||||||
resolved_program.store_definitions(program, imported_programs)?;
|
resolved_program.store_definitions(&program, imported_programs)?;
|
||||||
|
|
||||||
// Get default input
|
// Get default input
|
||||||
let default = input.pairs.get(&program_name);
|
let default = input.pairs.get(&program_name);
|
||||||
|
@ -28,7 +28,11 @@ use leo_imports::ImportParser;
|
|||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub fn store_definitions(&mut self, program: Program, imported_programs: &ImportParser) -> Result<(), ImportError> {
|
pub fn store_definitions(
|
||||||
|
&mut self,
|
||||||
|
program: &Program,
|
||||||
|
imported_programs: &ImportParser,
|
||||||
|
) -> Result<(), ImportError> {
|
||||||
let program_name = program.name.trim_end_matches(".leo");
|
let program_name = program.name.trim_end_matches(".leo");
|
||||||
|
|
||||||
// evaluate all import statements and store imported definitions
|
// evaluate all import statements and store imported definitions
|
||||||
@ -39,15 +43,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
.collect::<Result<Vec<_>, ImportError>>()?;
|
||||||
|
|
||||||
// evaluate and store all circuit definitions
|
// evaluate and store all circuit definitions
|
||||||
program.circuits.into_iter().for_each(|(identifier, circuit)| {
|
program.circuits.iter().for_each(|(identifier, circuit)| {
|
||||||
let resolved_circuit_name = new_scope(program_name, &identifier.name);
|
let resolved_circuit_name = new_scope(program_name, &identifier.name);
|
||||||
self.store(resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit));
|
self.store(
|
||||||
|
resolved_circuit_name,
|
||||||
|
ConstrainedValue::CircuitDefinition(circuit.clone()),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// evaluate and store all function definitions
|
// evaluate and store all function definitions
|
||||||
program.functions.into_iter().for_each(|(function_name, function)| {
|
program.functions.iter().for_each(|(function_name, function)| {
|
||||||
let resolved_function_name = new_scope(program_name, &function_name.name);
|
let resolved_function_name = new_scope(program_name, &function_name.name);
|
||||||
self.store(resolved_function_name, ConstrainedValue::Function(None, function));
|
self.store(
|
||||||
|
resolved_function_name,
|
||||||
|
ConstrainedValue::Function(None, function.clone()),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -19,8 +19,8 @@ use leo_grammar::ParserError;
|
|||||||
use leo_imports::ImportParserError;
|
use leo_imports::ImportParserError;
|
||||||
use leo_input::InputParserError;
|
use leo_input::InputParserError;
|
||||||
use leo_state::LocalDataVerificationError;
|
use leo_state::LocalDataVerificationError;
|
||||||
// use leo_symbol_table::SymbolTableError;
|
use leo_symbol_table::SymbolTableError;
|
||||||
// use leo_type_inference::TypeInferenceError;
|
use leo_type_inference::TypeInferenceError;
|
||||||
|
|
||||||
use bincode::Error as SerdeError;
|
use bincode::Error as SerdeError;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -68,11 +68,11 @@ pub enum CompilerError {
|
|||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
SerdeError(#[from] SerdeError),
|
SerdeError(#[from] SerdeError),
|
||||||
// #[error("{}", _0)]
|
|
||||||
// SymbolTableError(#[from] SymbolTableError),
|
|
||||||
|
|
||||||
// #[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
// TypeInferenceError(#[from] TypeInferenceError),
|
SymbolTableError(#[from] SymbolTableError),
|
||||||
|
#[error("{}", _0)]
|
||||||
|
TypeInferenceError(#[from] TypeInferenceError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerError {
|
impl CompilerError {
|
||||||
@ -81,8 +81,8 @@ impl CompilerError {
|
|||||||
CompilerError::InputParserError(error) => error.set_path(path),
|
CompilerError::InputParserError(error) => error.set_path(path),
|
||||||
CompilerError::FunctionError(error) => error.set_path(path),
|
CompilerError::FunctionError(error) => error.set_path(path),
|
||||||
CompilerError::OutputStringError(error) => error.set_path(path),
|
CompilerError::OutputStringError(error) => error.set_path(path),
|
||||||
// CompilerError::SymbolTableError(error) => error.set_path(path),
|
CompilerError::SymbolTableError(error) => error.set_path(path),
|
||||||
// CompilerError::TypeInferenceError(error) => error.set_path(path),
|
CompilerError::TypeInferenceError(error) => error.set_path(path),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
// 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::errors::ImportError;
|
|
||||||
use leo_ast::{Package, Program};
|
|
||||||
|
|
||||||
use std::{collections::HashMap, env::current_dir};
|
|
||||||
|
|
||||||
/// Parses all relevant import files for a program.
|
|
||||||
/// Stores compiled program structs.
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct ImportParser {
|
|
||||||
imports: HashMap<String, Program>,
|
|
||||||
core_packages: Vec<Package>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImportParser {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert_import(&mut self, file_name: String, program: Program) {
|
|
||||||
// todo: handle conflicting versions for duplicate imports here
|
|
||||||
let _res = self.imports.insert(file_name, program);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert_core_package(&mut self, package: &Package) {
|
|
||||||
let _res = self.core_packages.push(package.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_import(&self, file_name: &str) -> Option<&Program> {
|
|
||||||
self.imports.get(file_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn core_packages(&self) -> &Vec<Package> {
|
|
||||||
&self.core_packages
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(program: &Program) -> Result<Self, ImportError> {
|
|
||||||
let mut imports = Self::new();
|
|
||||||
|
|
||||||
// Find all imports relative to current directory
|
|
||||||
let path = current_dir().map_err(ImportError::current_directory_error)?;
|
|
||||||
|
|
||||||
// Parse each imported file
|
|
||||||
program
|
|
||||||
.imports
|
|
||||||
.iter()
|
|
||||||
.map(|import| imports.parse_package(path.clone(), &import.package))
|
|
||||||
.collect::<Result<Vec<()>, ImportError>>()?;
|
|
||||||
|
|
||||||
Ok(imports)
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@
|
|||||||
use crate::{errors::ImportError, ConstrainedProgram, GroupType};
|
use crate::{errors::ImportError, ConstrainedProgram, GroupType};
|
||||||
use leo_ast::ImportStatement;
|
use leo_ast::ImportStatement;
|
||||||
use leo_imports::ImportParser;
|
use leo_imports::ImportParser;
|
||||||
// use leo_symbol_table::imported_symbols::ImportedSymbols;
|
use leo_symbol_table::imported_symbols::ImportedSymbols;
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
@ -37,21 +37,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Fetch dependencies for the current import
|
// Fetch dependencies for the current import
|
||||||
// let imported_symbols = ImportedSymbols::new(import);
|
let imported_symbols = ImportedSymbols::new(import);
|
||||||
//
|
|
||||||
// for (name, symbol) in imported_symbols.symbols {
|
for (name, symbol) in imported_symbols.symbols {
|
||||||
// // Find imported program
|
// Find imported program
|
||||||
// let program = imported_programs
|
let program = imported_programs
|
||||||
// .get_import(&name)
|
.get_import(&name)
|
||||||
// .ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?;
|
.ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?;
|
||||||
//
|
|
||||||
// // Parse imported program
|
// Parse imported program
|
||||||
// self.store_definitions(program.clone(), imported_programs)?;
|
self.store_definitions(program, imported_programs)?;
|
||||||
//
|
|
||||||
// // Store the imported symbol
|
// Store the imported symbol
|
||||||
// self.store_symbol(scope, &name, &symbol, program)?;
|
self.store_symbol(scope, &name, &symbol, program)?;
|
||||||
// }
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
assert_satisfied,
|
assert_satisfied,
|
||||||
expect_compiler_error,
|
expect_compiler_error,
|
||||||
|
expect_type_inference_error,
|
||||||
get_output,
|
get_output,
|
||||||
parse_program,
|
parse_program,
|
||||||
parse_program_with_input,
|
parse_program_with_input,
|
||||||
@ -126,13 +127,13 @@ fn test_false_or_false() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_true_or_u32() {
|
fn test_true_or_u32() {
|
||||||
// let bytes = include_bytes!("true_or_u32.leo");
|
let bytes = include_bytes!("true_or_u32.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Boolean and &&
|
// Boolean and &&
|
||||||
|
|
||||||
@ -160,13 +161,13 @@ fn test_false_and_false() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_true_and_u32() {
|
fn test_true_and_u32() {
|
||||||
// let bytes = include_bytes!("true_and_u32.leo");
|
let bytes = include_bytes!("true_and_u32.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// All
|
// All
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, expect_compiler_error, parse_program};
|
use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, parse_program};
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
|
|
||||||
@ -34,13 +34,13 @@ fn test_inline_fail() {
|
|||||||
expect_compiler_error(program);
|
expect_compiler_error(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_inline_undefined() {
|
fn test_inline_undefined() {
|
||||||
// let bytes = include_bytes!("inline_undefined.leo");
|
let bytes = include_bytes!("inline_undefined.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
|
||||||
@ -52,13 +52,13 @@ fn test_member_variable() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_member_variable_fail() {
|
fn test_member_variable_fail() {
|
||||||
// let bytes = include_bytes!("member_variable_fail.leo");
|
let bytes = include_bytes!("member_variable_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_member_variable_and_function() {
|
fn test_member_variable_and_function() {
|
||||||
@ -76,21 +76,21 @@ fn test_member_function() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_member_function_fail() {
|
fn test_member_function_fail() {
|
||||||
// let bytes = include_bytes!("member_function_fail.leo");
|
let bytes = include_bytes!("member_function_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
expect_type_inference_error(error);
|
||||||
// fn test_member_function_invalid() {
|
}
|
||||||
// let bytes = include_bytes!("member_function_invalid.leo");
|
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
#[test]
|
||||||
//
|
fn test_member_function_invalid() {
|
||||||
// expect_type_inference_error(error);
|
let bytes = include_bytes!("member_function_invalid.leo");
|
||||||
// }
|
let error = parse_program(bytes).err().unwrap();
|
||||||
|
|
||||||
|
expect_type_inference_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_member_function_nested() {
|
fn test_member_function_nested() {
|
||||||
@ -116,31 +116,31 @@ fn test_member_static_function_nested() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_member_static_function_invalid() {
|
fn test_member_static_function_invalid() {
|
||||||
// let bytes = include_bytes!("member_static_function_invalid.leo");
|
let bytes = include_bytes!("member_static_function_invalid.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
expect_type_inference_error(error)
|
||||||
// fn test_member_static_function_undefined() {
|
}
|
||||||
// let bytes = include_bytes!("member_static_function_undefined.leo");
|
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
#[test]
|
||||||
//
|
fn test_member_static_function_undefined() {
|
||||||
// expect_type_inference_error(error)
|
let bytes = include_bytes!("member_static_function_undefined.leo");
|
||||||
// }
|
let error = parse_program(bytes).err().unwrap();
|
||||||
|
|
||||||
|
expect_type_inference_error(error)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutability
|
// Mutability
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_mutate_function_fail() {
|
fn test_mutate_function_fail() {
|
||||||
// let bytes = include_bytes!("mut_function_fail.leo");
|
let bytes = include_bytes!("mut_function_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_self_variable() {
|
fn test_mutate_self_variable() {
|
||||||
@ -158,29 +158,29 @@ fn test_mutate_self_variable_fail() {
|
|||||||
expect_compiler_error(program);
|
expect_compiler_error(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_mutate_self_function_fail() {
|
fn test_mutate_self_function_fail() {
|
||||||
// let bytes = include_bytes!("mut_self_function_fail.leo");
|
let bytes = include_bytes!("mut_self_function_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
expect_type_inference_error(error);
|
||||||
// fn test_mutate_self_static_function_fail() {
|
}
|
||||||
// let bytes = include_bytes!("mut_self_static_function_fail.leo");
|
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_mutate_static_function_fail() {
|
fn test_mutate_self_static_function_fail() {
|
||||||
// let bytes = include_bytes!("mut_static_function_fail.leo");
|
let bytes = include_bytes!("mut_self_static_function_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mutate_static_function_fail() {
|
||||||
|
let bytes = include_bytes!("mut_static_function_fail.leo");
|
||||||
|
let error = parse_program(bytes).err().unwrap();
|
||||||
|
|
||||||
|
expect_type_inference_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_variable() {
|
fn test_mutate_variable() {
|
||||||
@ -200,13 +200,13 @@ fn test_mutate_variable_fail() {
|
|||||||
|
|
||||||
// Self
|
// Self
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_self_fail() {
|
fn test_self_fail() {
|
||||||
// let bytes = include_bytes!("self_fail.leo");
|
let bytes = include_bytes!("self_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_self_member_pass() {
|
fn test_self_member_pass() {
|
||||||
@ -224,13 +224,13 @@ fn test_self_member_invalid() {
|
|||||||
let _err = expect_compiler_error(program);
|
let _err = expect_compiler_error(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_self_member_undefined() {
|
fn test_self_member_undefined() {
|
||||||
// let bytes = include_bytes!("self_member_undefined.leo");
|
let bytes = include_bytes!("self_member_undefined.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// All
|
// All
|
||||||
|
|
||||||
|
@ -16,39 +16,39 @@
|
|||||||
|
|
||||||
pub mod packages;
|
pub mod packages;
|
||||||
|
|
||||||
use crate::{assert_satisfied, parse_program};
|
use crate::{assert_satisfied, expect_symbol_table_error, parse_program};
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_core_circuit_invalid() {
|
fn test_core_circuit_invalid() {
|
||||||
// let program_bytes = include_bytes!("core_package_invalid.leo");
|
let program_bytes = include_bytes!("core_package_invalid.leo");
|
||||||
// let program = parse_program(program_bytes).err().unwrap();
|
let program = parse_program(program_bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_symbol_table_error(program);
|
expect_symbol_table_error(program);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_core_circuit_star_fail() {
|
fn test_core_circuit_star_fail() {
|
||||||
// let program_bytes = include_bytes!("core_circuit_star_fail.leo");
|
let program_bytes = include_bytes!("core_circuit_star_fail.leo");
|
||||||
// let error = parse_program(program_bytes).err().unwrap();
|
let error = parse_program(program_bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_symbol_table_error(error);
|
expect_symbol_table_error(error);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_core_package_invalid() {
|
fn test_core_package_invalid() {
|
||||||
// let program_bytes = include_bytes!("core_package_invalid.leo");
|
let program_bytes = include_bytes!("core_package_invalid.leo");
|
||||||
// let error = parse_program(program_bytes).err().unwrap();
|
let error = parse_program(program_bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_symbol_table_error(error);
|
expect_symbol_table_error(error);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_core_unstable_package_invalid() {
|
fn test_core_unstable_package_invalid() {
|
||||||
// let program_bytes = include_bytes!("core_unstable_package_invalid.leo");
|
let program_bytes = include_bytes!("core_unstable_package_invalid.leo");
|
||||||
// let error = parse_program(program_bytes).err().unwrap();
|
let error = parse_program(program_bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_symbol_table_error(error);
|
expect_symbol_table_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unstable_blake2s_sanity() {
|
fn test_unstable_blake2s_sanity() {
|
||||||
|
@ -14,7 +14,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, generate_main_input, get_output, parse_program, parse_program_with_input};
|
use crate::{
|
||||||
|
assert_satisfied,
|
||||||
|
expect_type_inference_error,
|
||||||
|
generate_main_input,
|
||||||
|
get_output,
|
||||||
|
parse_program,
|
||||||
|
parse_program_with_input,
|
||||||
|
};
|
||||||
|
|
||||||
use leo_ast::InputValue;
|
use leo_ast::InputValue;
|
||||||
use leo_input::types::{IntegerType, U8Type, UnsignedIntegerType};
|
use leo_input::types::{IntegerType, U8Type, UnsignedIntegerType};
|
||||||
@ -22,22 +29,22 @@ use rand::{Rng, SeedableRng};
|
|||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use snarkos_algorithms::prf::blake2s::Blake2s as B2SPRF;
|
use snarkos_algorithms::prf::blake2s::Blake2s as B2SPRF;
|
||||||
use snarkos_models::algorithms::PRF;
|
use snarkos_models::algorithms::PRF;
|
||||||
//
|
|
||||||
// #[test]
|
|
||||||
// fn test_arguments_length_fail() {
|
|
||||||
// let program_bytes = include_bytes!("arguments_length_fail.leo");
|
|
||||||
// let error = parse_program(program_bytes).err().unwrap();
|
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_arguments_type_fail() {
|
fn test_arguments_length_fail() {
|
||||||
// let program_bytes = include_bytes!("arguments_type_fail.leo");
|
let program_bytes = include_bytes!("arguments_length_fail.leo");
|
||||||
// let error = parse_program(program_bytes).err().unwrap();
|
let error = parse_program(program_bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_arguments_type_fail() {
|
||||||
|
let program_bytes = include_bytes!("arguments_type_fail.leo");
|
||||||
|
let error = parse_program(program_bytes).err().unwrap();
|
||||||
|
|
||||||
|
expect_type_inference_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blake2s_input() {
|
fn test_blake2s_input() {
|
||||||
|
@ -14,7 +14,14 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, expect_compiler_error, get_output, parse_program, parse_program_with_input};
|
use crate::{
|
||||||
|
assert_satisfied,
|
||||||
|
expect_compiler_error,
|
||||||
|
expect_type_inference_error,
|
||||||
|
get_output,
|
||||||
|
parse_program,
|
||||||
|
parse_program_with_input,
|
||||||
|
};
|
||||||
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -110,13 +117,13 @@ fn test_scope_fail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_undefined() {
|
fn test_undefined() {
|
||||||
// let bytes = include_bytes!("undefined.leo");
|
let bytes = include_bytes!("undefined.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_value_unchanged() {
|
fn test_value_unchanged() {
|
||||||
@ -126,13 +133,13 @@ fn test_value_unchanged() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_array_input() {
|
fn test_array_input() {
|
||||||
// let bytes = include_bytes!("array_input.leo");
|
let bytes = include_bytes!("array_input.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error)
|
expect_type_inference_error(error)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Test return multidimensional arrays
|
// Test return multidimensional arrays
|
||||||
|
|
||||||
|
@ -180,14 +180,14 @@ pub(crate) fn expect_compiler_error(program: EdwardsTestCompiler) -> CompilerErr
|
|||||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
program.generate_constraints_helper(&mut cs).unwrap_err()
|
program.generate_constraints_helper(&mut cs).unwrap_err()
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// pub(crate) fn expect_type_inference_error(error: CompilerError) {
|
|
||||||
// assert!(matches!(error, CompilerError::TypeInferenceError(_)))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub(crate) fn expect_symbol_table_error(error: CompilerError) {
|
pub(crate) fn expect_type_inference_error(error: CompilerError) {
|
||||||
// assert!(matches!(error, CompilerError::SymbolTableError(_)))
|
assert!(matches!(error, CompilerError::TypeInferenceError(_)))
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
pub(crate) fn expect_symbol_table_error(error: CompilerError) {
|
||||||
|
assert!(matches!(error, CompilerError::SymbolTableError(_)))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn generate_main_input(input: Vec<(&str, Option<InputValue>)>) -> MainInput {
|
pub(crate) fn generate_main_input(input: Vec<(&str, Option<InputValue>)>) -> MainInput {
|
||||||
let mut main_input = MainInput::new();
|
let mut main_input = MainInput::new();
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, expect_compiler_error, generate_main_input, parse_program};
|
use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, generate_main_input, parse_program};
|
||||||
use leo_ast::InputValue;
|
use leo_ast::InputValue;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -89,21 +89,21 @@ fn test_circuit_variable_mut() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_circuit_function_mut() {
|
fn test_circuit_function_mut() {
|
||||||
// let bytes = include_bytes!("circuit_function_mut.leo");
|
let bytes = include_bytes!("circuit_function_mut.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_circuit_static_function_mut() {
|
fn test_circuit_static_function_mut() {
|
||||||
// let bytes = include_bytes!("circuit_static_function_mut.leo");
|
let bytes = include_bytes!("circuit_static_function_mut.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_function_input() {
|
fn test_function_input() {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, generate_main_input, parse_program};
|
use crate::{assert_satisfied, expect_type_inference_error, generate_main_input, parse_program};
|
||||||
use leo_ast::InputValue;
|
use leo_ast::InputValue;
|
||||||
|
|
||||||
pub mod conditional;
|
pub mod conditional;
|
||||||
@ -57,10 +57,10 @@ fn test_iteration_basic() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_num_returns_fail() {
|
fn test_num_returns_fail() {
|
||||||
// let bytes = include_bytes!("num_returns_fail.leo");
|
let bytes = include_bytes!("num_returns_fail.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// expect_type_inference_error(error);
|
expect_type_inference_error(error);
|
||||||
// }
|
}
|
||||||
|
@ -18,7 +18,7 @@ use crate::{expect_compiler_error, parse_input, parse_program};
|
|||||||
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
||||||
use leo_grammar::ParserError;
|
use leo_grammar::ParserError;
|
||||||
use leo_input::InputParserError;
|
use leo_input::InputParserError;
|
||||||
// use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError};
|
use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError};
|
||||||
|
|
||||||
pub mod identifiers;
|
pub mod identifiers;
|
||||||
|
|
||||||
@ -75,16 +75,16 @@ fn input_syntax_error() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_compare_mismatched_types() {
|
fn test_compare_mismatched_types() {
|
||||||
// let bytes = include_bytes!("compare_mismatched_types.leo");
|
let bytes = include_bytes!("compare_mismatched_types.leo");
|
||||||
// let error = parse_program(bytes).err().unwrap();
|
let error = parse_program(bytes).err().unwrap();
|
||||||
//
|
|
||||||
// // Expect a type inference error.
|
// Expect a type inference error.
|
||||||
// match error {
|
match error {
|
||||||
// CompilerError::TypeInferenceError(TypeInferenceError::FrameError(FrameError::TypeAssertionError(
|
CompilerError::TypeInferenceError(TypeInferenceError::FrameError(FrameError::TypeAssertionError(
|
||||||
// TypeAssertionError::Error(_),
|
TypeAssertionError::Error(_),
|
||||||
// ))) => {}
|
))) => {}
|
||||||
// error => panic!("Expected type inference error, found {}", error),
|
error => panic!("Expected type inference error, found {}", error),
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This module contains the [`Grammar`] type, a wrapper around the [`File`] type in this module.
|
//! This module contains the [`Grammar`] type, a wrapper around the [`File`] type in this module.
|
||||||
//! The [`Grammar`] type is the datatype generated by the pest parser using grammar from `leo.pest`.
|
//! The [`Grammar`] type is the datatype generated by the pest parser using grammar from `leo.pest`.
|
||||||
//! The [`Grammar`] type is intended to be parsed into a [`LeoAst`]. It should not be parsed by
|
//! The [`Grammar`] type is intended to be parsed into a [`Ast`]. It should not be parsed by
|
||||||
//! any other pass of the compiler.
|
//! any other pass of the compiler.
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -60,7 +60,7 @@ use std::{fs, path::Path};
|
|||||||
/// These data types form a tree that begins from a [`File`] type root.
|
/// These data types form a tree that begins from a [`File`] type root.
|
||||||
///
|
///
|
||||||
/// A new [`Grammar`] type can be created from a `*.leo` file at a [`Path`].
|
/// A new [`Grammar`] type can be created from a `*.leo` file at a [`Path`].
|
||||||
/// A [`Grammar`] type can be used to create a new [`LeoAst`] type.
|
/// A [`Grammar`] type can be used to create a new [`Ast`] type.
|
||||||
pub struct Grammar<'ast> {
|
pub struct Grammar<'ast> {
|
||||||
ast: files::File<'ast>,
|
ast: files::File<'ast>,
|
||||||
}
|
}
|
||||||
|
40
symbol-table/Cargo.toml
Normal file
40
symbol-table/Cargo.toml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[package]
|
||||||
|
name = "leo-symbol-table"
|
||||||
|
version = "1.0.4"
|
||||||
|
authors = [ "The Aleo Team <hello@aleo.org>" ]
|
||||||
|
description = "Stores user-defined variables during type resolution"
|
||||||
|
homepage = "https://aleo.org"
|
||||||
|
repository = "https://github.com/AleoHQ/leo"
|
||||||
|
keywords = [
|
||||||
|
"aleo",
|
||||||
|
"cryptography",
|
||||||
|
"leo",
|
||||||
|
"programming-language",
|
||||||
|
"zero-knowledge"
|
||||||
|
]
|
||||||
|
categories = [ "cryptography::croptocurrencies", "web-programming" ]
|
||||||
|
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies.leo-ast]
|
||||||
|
path = "../ast"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-core]
|
||||||
|
path = "../core"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-grammar]
|
||||||
|
path = "../grammar"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-imports]
|
||||||
|
path = "../imports"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.thiserror]
|
||||||
|
version = "1.0"
|
24
symbol-table/src/attributes/attribute.rs
Normal file
24
symbol-table/src/attributes/attribute.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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 serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Indicates that a program variable has additional functionality.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub enum Attribute {
|
||||||
|
Mutable,
|
||||||
|
Static,
|
||||||
|
}
|
18
symbol-table/src/attributes/mod.rs
Normal file
18
symbol-table/src/attributes/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod attribute;
|
||||||
|
pub use self::attribute::*;
|
21
symbol-table/src/errors/mod.rs
Normal file
21
symbol-table/src/errors/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod symbol_table;
|
||||||
|
pub use self::symbol_table::*;
|
||||||
|
|
||||||
|
pub mod type_;
|
||||||
|
pub use self::type_::*;
|
100
symbol-table/src/errors/symbol_table.rs
Normal file
100
symbol-table/src/errors/symbol_table.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// 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::{TypeError, UserDefinedType};
|
||||||
|
use leo_ast::{Error as FormattedError, ImportSymbol, Program, Span};
|
||||||
|
use leo_core::{CorePackageListError, LeoCorePackageError};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when tracking variable, function, and circuit names in a program.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum SymbolTableError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
CorePackageListError(#[from] CorePackageListError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
LeoCorePackageError(#[from] LeoCorePackageError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
TypeError(#[from] TypeError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolTableError {
|
||||||
|
///
|
||||||
|
/// Sets the filepath for the error stacktrace.
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
SymbolTableError::CorePackageListError(error) => error.set_path(path),
|
||||||
|
SymbolTableError::Error(error) => error.set_path(path),
|
||||||
|
SymbolTableError::LeoCorePackageError(error) => error.set_path(path),
|
||||||
|
SymbolTableError::TypeError(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a new formatted error with a given message and span information.
|
||||||
|
///
|
||||||
|
fn new_from_span(message: String, span: Span) -> Self {
|
||||||
|
SymbolTableError::Error(FormattedError::new_from_span(message, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Two circuits have been defined with the same name.
|
||||||
|
///
|
||||||
|
pub fn duplicate_circuit(variable: UserDefinedType) -> Self {
|
||||||
|
let message = format!("Duplicate circuit definition found for `{}`", variable.identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, variable.identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Two functions have been defined with the same name.
|
||||||
|
///
|
||||||
|
pub fn duplicate_function(variable: UserDefinedType) -> Self {
|
||||||
|
let message = format!("Duplicate function definition found for `{}`", variable.identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, variable.identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to access a package name that is not defined.
|
||||||
|
///
|
||||||
|
pub fn unknown_package(name: &str, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Cannot find imported package `{}` in source files or import directory",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to import a name that is not defined in the current file.
|
||||||
|
///
|
||||||
|
pub fn unknown_symbol(symbol: &ImportSymbol, program: &Program) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Cannot find imported symbol `{}` in imported file `{}`",
|
||||||
|
symbol, program.name
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, symbol.span.to_owned())
|
||||||
|
}
|
||||||
|
}
|
86
symbol-table/src/errors/type_.rs
Normal file
86
symbol-table/src/errors/type_.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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_ast::{Error as FormattedError, Identifier, Span};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when resolving types.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TypeError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace.
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
TypeError::Error(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new formatted error with a given message and span information.
|
||||||
|
///
|
||||||
|
fn new_from_span(message: String, span: Span) -> Self {
|
||||||
|
TypeError::Error(FormattedError::new_from_span(message, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The `Self` keyword was used outside of a circuit.
|
||||||
|
///
|
||||||
|
pub fn self_not_available(span: Span) -> Self {
|
||||||
|
let message = "Type `Self` is only available in circuit definitions and circuit functions.".to_string();
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Found an unknown circuit name.
|
||||||
|
///
|
||||||
|
pub fn undefined_circuit(identifier: Identifier) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Type circuit `{}` must be defined before it is used in an expression.",
|
||||||
|
identifier.name
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Found an unknown circuit member name.
|
||||||
|
///
|
||||||
|
pub fn undefined_circuit_member(identifier: Identifier) -> Self {
|
||||||
|
let message = format!("Circuit has no member `{}`.", identifier.name);
|
||||||
|
|
||||||
|
Self::new_from_span(message, identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Found an unknown function name.
|
||||||
|
///
|
||||||
|
pub fn undefined_function(identifier: Identifier) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Type function `{}` must be defined before it is used in an expression.",
|
||||||
|
identifier.name
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, identifier.span)
|
||||||
|
}
|
||||||
|
}
|
57
symbol-table/src/imports/imported_symbols.rs
Normal file
57
symbol-table/src/imports/imported_symbols.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// 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_ast::{ImportStatement, ImportSymbol, Package, PackageAccess};
|
||||||
|
|
||||||
|
/// Stores the the package file name and imported symbol from an import statement
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImportedSymbols {
|
||||||
|
pub symbols: Vec<(String, ImportSymbol)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedSymbols {
|
||||||
|
pub fn new(import: &ImportStatement) -> Self {
|
||||||
|
let mut imported_symbols = Self::default();
|
||||||
|
|
||||||
|
imported_symbols.push_package(&import.package);
|
||||||
|
|
||||||
|
imported_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_package(&mut self, package: &Package) {
|
||||||
|
self.push_package_access(package.name.name.clone(), &package.access);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_package_access(&mut self, package: String, access: &PackageAccess) {
|
||||||
|
match access {
|
||||||
|
PackageAccess::SubPackage(package) => self.push_package(package),
|
||||||
|
PackageAccess::Star(span) => {
|
||||||
|
let star = ImportSymbol::star(span);
|
||||||
|
self.symbols.push((package, star));
|
||||||
|
}
|
||||||
|
PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())),
|
||||||
|
PackageAccess::Multiple(packages) => packages
|
||||||
|
.iter()
|
||||||
|
.for_each(|access| self.push_package_access(package.clone(), access)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ImportedSymbols {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { symbols: Vec::new() }
|
||||||
|
}
|
||||||
|
}
|
18
symbol-table/src/imports/mod.rs
Normal file
18
symbol-table/src/imports/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod imported_symbols;
|
||||||
|
pub use self::imported_symbols::*;
|
41
symbol-table/src/lib.rs
Normal file
41
symbol-table/src/lib.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! The symbol table for a Leo program.
|
||||||
|
//!
|
||||||
|
//! This module contains the [`SymbolTable`] type, an abstract data type that tracks the current
|
||||||
|
//! bindings for functions and circuits in a Leo program.
|
||||||
|
//!
|
||||||
|
//! A new [`Symbol Table`] type can be created from a reference to a [`LeoAst`].
|
||||||
|
//! A [`Symbol Table`] type can be used to create a new [`TypeInference`] type.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate thiserror;
|
||||||
|
|
||||||
|
pub mod attributes;
|
||||||
|
pub use self::attributes::*;
|
||||||
|
|
||||||
|
pub mod errors;
|
||||||
|
pub use self::errors::*;
|
||||||
|
|
||||||
|
pub mod imports;
|
||||||
|
pub use self::imports::*;
|
||||||
|
|
||||||
|
pub mod symbol_table;
|
||||||
|
pub use self::symbol_table::*;
|
||||||
|
|
||||||
|
pub mod types;
|
||||||
|
pub use self::types::*;
|
502
symbol-table/src/symbol_table.rs
Normal file
502
symbol-table/src/symbol_table.rs
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
// 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::{CircuitType, CircuitVariableType, FunctionType, ImportedSymbols, SymbolTableError, UserDefinedType};
|
||||||
|
use leo_ast::{Circuit, Function, Identifier, ImportStatement, ImportSymbol, Input, Package, Program};
|
||||||
|
use leo_core::CorePackageList;
|
||||||
|
use leo_imports::ImportParser;
|
||||||
|
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
pub const INPUT_VARIABLE_NAME: &str = "input";
|
||||||
|
pub const RECORD_VARIABLE_NAME: &str = "record";
|
||||||
|
pub const REGISTERS_VARIABLE_NAME: &str = "registers";
|
||||||
|
pub const STATE_VARIABLE_NAME: &str = "state";
|
||||||
|
pub const STATE_LEAF_VARIABLE_NAME: &str = "state_leaf";
|
||||||
|
|
||||||
|
/// The symbol table for a Leo program.
|
||||||
|
///
|
||||||
|
/// A symbol table has access to all function and circuit names in its parent's symbol table.
|
||||||
|
/// A symbol table cannot access names in its child's symbol table.
|
||||||
|
/// A child symbol table cannot access names in another sibling's symbol table.
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct SymbolTable {
|
||||||
|
/// Maps name -> parameter type.
|
||||||
|
names: HashMap<String, UserDefinedType>,
|
||||||
|
|
||||||
|
/// Maps circuit name -> circuit type.
|
||||||
|
circuits: HashMap<String, CircuitType>,
|
||||||
|
|
||||||
|
/// Maps function name -> function type.
|
||||||
|
functions: HashMap<String, FunctionType>,
|
||||||
|
|
||||||
|
/// The parent of this symbol table.
|
||||||
|
parent: Option<Box<SymbolTable>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolTable {
|
||||||
|
///
|
||||||
|
/// Returns a new `SymbolTable` from a given, program, imported programs, and program input.
|
||||||
|
///
|
||||||
|
/// Checks that each circuit or function name is unique.
|
||||||
|
/// Unique names are added to a table of name -> user defined type.
|
||||||
|
///
|
||||||
|
/// Checks that each circuit or function definition contains valid types.
|
||||||
|
///
|
||||||
|
pub fn new(
|
||||||
|
program: &Program,
|
||||||
|
import_parser: &ImportParser,
|
||||||
|
input: &Input,
|
||||||
|
) -> Result<SymbolTable, SymbolTableError> {
|
||||||
|
// Create a new symbol table.
|
||||||
|
let mut table = Self::default();
|
||||||
|
|
||||||
|
// Insert input types into symbol table.
|
||||||
|
table.insert_input(input)?;
|
||||||
|
|
||||||
|
// Check for duplicate program and import names.
|
||||||
|
table.check_names(program, import_parser)?;
|
||||||
|
|
||||||
|
// Check for unknown or invalid types.
|
||||||
|
table.check_types(program)?;
|
||||||
|
|
||||||
|
Ok(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a function or circuit name into the symbol table from a given name and variable type.
|
||||||
|
///
|
||||||
|
/// If the symbol table did not have this name present, `None` is returned.
|
||||||
|
/// If the symbol table did have this name present, the variable type is updated, and the old
|
||||||
|
/// variable type is returned.
|
||||||
|
///
|
||||||
|
pub fn insert_name(&mut self, name: String, variable_type: UserDefinedType) -> Option<UserDefinedType> {
|
||||||
|
self.names.insert(name, variable_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a circuit name into the symbol table from a given name and variable type.
|
||||||
|
///
|
||||||
|
/// Returns an error if the circuit name is a duplicate.
|
||||||
|
///
|
||||||
|
pub fn insert_circuit_name(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
variable_type: UserDefinedType,
|
||||||
|
) -> Result<(), SymbolTableError> {
|
||||||
|
// Check that the circuit name is unique.
|
||||||
|
match self.insert_name(name, variable_type) {
|
||||||
|
Some(duplicate) => Err(SymbolTableError::duplicate_circuit(duplicate)),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a function name into the symbol table from a given name and variable type.
|
||||||
|
///
|
||||||
|
/// Returns an error if the function name is a duplicate.
|
||||||
|
///
|
||||||
|
pub fn insert_function_name(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
variable_type: UserDefinedType,
|
||||||
|
) -> Result<(), SymbolTableError> {
|
||||||
|
// Check that the circuit name is unique.
|
||||||
|
match self.insert_name(name, variable_type) {
|
||||||
|
Some(duplicate) => Err(SymbolTableError::duplicate_function(duplicate)),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a circuit definition into the symbol table from a given circuit identifier and
|
||||||
|
/// circuit type.
|
||||||
|
///
|
||||||
|
/// If the symbol table did not have this name present, `None` is returned.
|
||||||
|
/// If the symbol table did have this name present, the circuit type is updated, and the old
|
||||||
|
/// circuit type is returned.
|
||||||
|
///
|
||||||
|
pub fn insert_circuit_type(&mut self, identifier: Identifier, circuit_type: CircuitType) -> Option<CircuitType> {
|
||||||
|
self.circuits.insert(identifier.name, circuit_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a function definition into the symbol table from a given identifier and
|
||||||
|
/// function type.
|
||||||
|
///
|
||||||
|
/// If the symbol table did not have this name present, `None` is returned.
|
||||||
|
/// If the symbol table did have this name present, the function type is updated, and the old
|
||||||
|
/// function type is returned.
|
||||||
|
///
|
||||||
|
pub fn insert_function_type(
|
||||||
|
&mut self,
|
||||||
|
identifier: Identifier,
|
||||||
|
function_type: FunctionType,
|
||||||
|
) -> Option<FunctionType> {
|
||||||
|
self.functions.insert(identifier.name, function_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the circuit type corresponding to the name.
|
||||||
|
///
|
||||||
|
/// If the symbol table did not have this name present, then the parent symbol table is checked.
|
||||||
|
/// If there is no parent symbol table, then `None` is returned.
|
||||||
|
///
|
||||||
|
pub fn get_circuit_type(&self, name: &str) -> Option<&CircuitType> {
|
||||||
|
// Lookup name in symbol table.
|
||||||
|
match self.circuits.get(name) {
|
||||||
|
Some(circuit) => Some(circuit),
|
||||||
|
None => {
|
||||||
|
// Lookup name in parent symbol table.
|
||||||
|
match &self.parent {
|
||||||
|
Some(parent) => parent.get_circuit_type(name),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the function type corresponding to the name.
|
||||||
|
///
|
||||||
|
/// If the symbol table did not have this name present, then the parent symbol table is checked.
|
||||||
|
/// If there is no parent symbol table, then `None` is returned.
|
||||||
|
///
|
||||||
|
pub fn get_function_type(&self, name: &str) -> Option<&FunctionType> {
|
||||||
|
// Lookup name in symbol table.
|
||||||
|
match self.functions.get(name) {
|
||||||
|
Some(circuit) => Some(circuit),
|
||||||
|
None => {
|
||||||
|
// Lookup name in parent symbol table
|
||||||
|
match &self.parent {
|
||||||
|
Some(parent) => parent.get_function_type(name),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for duplicate import, circuit, and function names given a program.
|
||||||
|
///
|
||||||
|
/// If a circuit or function name has no duplicates, then it is inserted into the symbol table.
|
||||||
|
/// Variables defined later in the unresolved program cannot have the same name.
|
||||||
|
///
|
||||||
|
pub fn check_names(&mut self, program: &Program, import_parser: &ImportParser) -> Result<(), SymbolTableError> {
|
||||||
|
// Check unresolved program import names.
|
||||||
|
self.check_import_names(&program.imports, import_parser)?;
|
||||||
|
|
||||||
|
// Check unresolved program circuit names.
|
||||||
|
self.check_circuit_names(&program.circuits)?;
|
||||||
|
|
||||||
|
// Check unresolved program function names.
|
||||||
|
self.check_function_names(&program.functions)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for duplicate circuit names given a hashmap of circuits.
|
||||||
|
///
|
||||||
|
/// If a circuit name has no duplicates, then it is inserted into the symbol table.
|
||||||
|
/// Types defined later in the program cannot have the same name.
|
||||||
|
///
|
||||||
|
pub fn check_circuit_names(&mut self, circuits: &HashMap<Identifier, Circuit>) -> Result<(), SymbolTableError> {
|
||||||
|
// Iterate over circuit names and definitions.
|
||||||
|
for (identifier, circuit) in circuits.iter() {
|
||||||
|
// Attempt to insert the circuit name into the symbol table.
|
||||||
|
self.insert_circuit_name(identifier.to_string(), UserDefinedType::from(circuit.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for duplicate function names given a hashmap of functions.
|
||||||
|
///
|
||||||
|
/// If a function name has no duplicates, then it is inserted into the symbol table.
|
||||||
|
/// Types defined later in the program cannot have the same name.
|
||||||
|
///
|
||||||
|
pub fn check_function_names(&mut self, functions: &HashMap<Identifier, Function>) -> Result<(), SymbolTableError> {
|
||||||
|
// Iterate over function names and definitions.
|
||||||
|
for (identifier, function) in functions.iter() {
|
||||||
|
// Attempt to insert the function name into the symbol table.
|
||||||
|
self.insert_function_name(identifier.to_string(), UserDefinedType::from(function.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks that all given imported names exist in the list of imported programs.
|
||||||
|
///
|
||||||
|
/// Additionally checks for duplicate imported names in the given vector of imports.
|
||||||
|
/// Types defined later in the program cannot have the same name.
|
||||||
|
///
|
||||||
|
pub fn check_import_names(
|
||||||
|
&mut self,
|
||||||
|
imports: &[ImportStatement],
|
||||||
|
import_parser: &ImportParser,
|
||||||
|
) -> Result<(), SymbolTableError> {
|
||||||
|
// Iterate over imported names.
|
||||||
|
for import in imports {
|
||||||
|
self.check_import_statement(import, import_parser)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks that a given import statement imports an existing package.
|
||||||
|
///
|
||||||
|
/// Additionally checks for duplicate imported names in the given vector of imports.
|
||||||
|
/// Types defined later in the program cannot have the same name.
|
||||||
|
///
|
||||||
|
pub fn check_import_statement(
|
||||||
|
&mut self,
|
||||||
|
import: &ImportStatement,
|
||||||
|
import_parser: &ImportParser,
|
||||||
|
) -> Result<(), SymbolTableError> {
|
||||||
|
// Check if the import name exists as core package.
|
||||||
|
let core_package = import_parser.get_core_package(&import.package);
|
||||||
|
|
||||||
|
// If the core package exists, then attempt to insert the import into the symbol table.
|
||||||
|
if let Some(package) = core_package {
|
||||||
|
return self.check_core_package(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to insert the imported names into the symbol table.
|
||||||
|
self.check_package(import, import_parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts imported core package circuit names and types into the symbol table.
|
||||||
|
///
|
||||||
|
/// Checks that the core package and all circuit names exist. Checks that imported circuit types
|
||||||
|
/// only contain known types.
|
||||||
|
///
|
||||||
|
pub fn check_core_package(&mut self, package: &Package) -> Result<(), SymbolTableError> {
|
||||||
|
// Create list of imported core packages.
|
||||||
|
let list = CorePackageList::from_package_access(package.access.to_owned())?;
|
||||||
|
|
||||||
|
// Fetch core package symbols from `leo-core`.
|
||||||
|
let symbol_list = list.to_symbols()?;
|
||||||
|
|
||||||
|
// Insert name and type information for each core package symbol.
|
||||||
|
for (name, circuit) in symbol_list.symbols() {
|
||||||
|
// Store name of symbol.
|
||||||
|
self.insert_circuit_name(name.to_string(), UserDefinedType::from(circuit.clone()))?;
|
||||||
|
|
||||||
|
// Create new circuit type for symbol.
|
||||||
|
let circuit_type = CircuitType::new(&self, circuit.to_owned())?;
|
||||||
|
|
||||||
|
// Insert circuit type of symbol.
|
||||||
|
self.insert_circuit_type(circuit_type.identifier.clone(), circuit_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts one or more imported symbols for a given imported package.
|
||||||
|
///
|
||||||
|
/// Checks that the package and all circuit and function names exist. Checks that imported circuit
|
||||||
|
/// and function types only contain known types.
|
||||||
|
///
|
||||||
|
pub fn check_package(
|
||||||
|
&mut self,
|
||||||
|
import: &ImportStatement,
|
||||||
|
import_parser: &ImportParser,
|
||||||
|
) -> Result<(), SymbolTableError> {
|
||||||
|
// Get imported symbols from statement.
|
||||||
|
let imported_symbols = ImportedSymbols::new(import);
|
||||||
|
|
||||||
|
// Import all symbols from an imported file for now.
|
||||||
|
// Keep track of which import files have already been checked.
|
||||||
|
let mut checked = HashSet::new();
|
||||||
|
|
||||||
|
// Iterate over each imported symbol.
|
||||||
|
for (name, symbol) in imported_symbols.symbols {
|
||||||
|
// Find the imported program.
|
||||||
|
let program = import_parser
|
||||||
|
.get_import(&name)
|
||||||
|
.ok_or_else(|| SymbolTableError::unknown_package(&name, &symbol.span))?;
|
||||||
|
|
||||||
|
// Push the imported file's name to checked import files.
|
||||||
|
if !checked.insert(name) {
|
||||||
|
// Skip the imported symbol if we have already checked the file.
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check the imported program for duplicate types.
|
||||||
|
self.check_names(program, import_parser)?;
|
||||||
|
|
||||||
|
// Check the imported program for undefined types.
|
||||||
|
self.check_types(program)?;
|
||||||
|
|
||||||
|
// Store the imported symbol.
|
||||||
|
// self.insert_import_symbol(symbol, program)?; // TODO (collinc97) uncomment this line when public/private import scopes are implemented.
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts the imported symbol into the symbol table if it is present in the given program.
|
||||||
|
///
|
||||||
|
pub fn insert_import_symbol(&mut self, symbol: ImportSymbol, program: &Program) -> Result<(), SymbolTableError> {
|
||||||
|
// Check for import *.
|
||||||
|
if symbol.is_star() {
|
||||||
|
// Insert all program circuits.
|
||||||
|
self.check_circuit_names(&program.circuits)?;
|
||||||
|
|
||||||
|
// Insert all program functions.
|
||||||
|
self.check_function_names(&program.functions)
|
||||||
|
} else {
|
||||||
|
// Check for a symbol alias.
|
||||||
|
let identifier = symbol.alias.to_owned().unwrap_or_else(|| symbol.symbol.to_owned());
|
||||||
|
|
||||||
|
// Check if the imported symbol is a circuit
|
||||||
|
match program.circuits.get(&symbol.symbol) {
|
||||||
|
Some(circuit) => {
|
||||||
|
// Insert imported circuit.
|
||||||
|
self.insert_circuit_name(identifier.to_string(), UserDefinedType::from(circuit.to_owned()))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Check if the imported symbol is a function.
|
||||||
|
match program.functions.get(&symbol.symbol) {
|
||||||
|
Some(function) => {
|
||||||
|
// Insert the imported function.
|
||||||
|
self.insert_function_name(
|
||||||
|
identifier.to_string(),
|
||||||
|
UserDefinedType::from(function.to_owned()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => Err(SymbolTableError::unknown_symbol(&symbol, program)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for unknown types in circuit and function definitions given an unresolved program.
|
||||||
|
///
|
||||||
|
/// If a circuit or function definition only contains known types, then it is inserted into the
|
||||||
|
/// symbol table. Variables defined later in the unresolved program can lookup the definition and
|
||||||
|
/// refer to its expected types.
|
||||||
|
///
|
||||||
|
pub fn check_types(&mut self, program: &Program) -> Result<(), SymbolTableError> {
|
||||||
|
// Check unresolved program circuit definitions.
|
||||||
|
self.check_types_circuits(&program.circuits)?;
|
||||||
|
|
||||||
|
// Check unresolved program function definitions.
|
||||||
|
self.check_types_functions(&program.functions)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for unknown types in a circuit given a hashmap of circuits.
|
||||||
|
///
|
||||||
|
/// If a circuit definition only contains known types, then it is inserted into the
|
||||||
|
/// symbol table. Variables defined later in the program can lookup the definition
|
||||||
|
/// and refer to its expected types
|
||||||
|
///
|
||||||
|
pub fn check_types_circuits(&mut self, circuits: &HashMap<Identifier, Circuit>) -> Result<(), SymbolTableError> {
|
||||||
|
// Iterate over circuit names and definitions.
|
||||||
|
for circuit in circuits.values() {
|
||||||
|
// Get the identifier of the circuit.
|
||||||
|
let identifier = circuit.circuit_name.clone();
|
||||||
|
|
||||||
|
// Resolve unknown types in the circuit definition.
|
||||||
|
let circuit_type = CircuitType::new(self, circuit.clone())?;
|
||||||
|
|
||||||
|
// Attempt to insert the circuit definition into the symbol table.
|
||||||
|
self.insert_circuit_type(identifier, circuit_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks for unknown types in a function given a hashmap of functions.
|
||||||
|
///
|
||||||
|
/// If a function definition only contains known types, then it is inserted into the
|
||||||
|
/// symbol table. Variables defined later in the program can lookup the definition
|
||||||
|
/// and refer to its expected types
|
||||||
|
///
|
||||||
|
pub fn check_types_functions(&mut self, functions: &HashMap<Identifier, Function>) -> Result<(), SymbolTableError> {
|
||||||
|
// Iterate over function names and definitions.
|
||||||
|
for function in functions.values() {
|
||||||
|
// Get the identifier of the function.
|
||||||
|
let identifier = function.identifier.clone();
|
||||||
|
|
||||||
|
// Resolve unknown types in the function definition.
|
||||||
|
let function_type = FunctionType::new(&self, function.clone())?;
|
||||||
|
|
||||||
|
// Attempt to insert the function definition into the symbol table.
|
||||||
|
self.insert_function_type(identifier, function_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts function input types into the symbol table.
|
||||||
|
///
|
||||||
|
/// Creates a new `CircuitType` to represent the input values.
|
||||||
|
/// The new type contains register, record, state, and state leaf circuit variables.
|
||||||
|
/// This allows easy access to input types using dot syntax: `input.register.r0`.
|
||||||
|
///
|
||||||
|
pub fn insert_input(&mut self, input: &Input) -> Result<(), SymbolTableError> {
|
||||||
|
// Get values for each input section.
|
||||||
|
let registers_values = input.get_registers().values();
|
||||||
|
let record_values = input.get_record().values();
|
||||||
|
let state_values = input.get_state().values();
|
||||||
|
let state_leaf_values = input.get_state_leaf().values();
|
||||||
|
|
||||||
|
// Create a new `CircuitType` for each input section.
|
||||||
|
let registers_type =
|
||||||
|
CircuitType::from_input_section(&self, REGISTERS_VARIABLE_NAME.to_string(), registers_values)?;
|
||||||
|
let record_type = CircuitType::from_input_section(&self, RECORD_VARIABLE_NAME.to_string(), record_values)?;
|
||||||
|
let state_type = CircuitType::from_input_section(&self, STATE_VARIABLE_NAME.to_string(), state_values)?;
|
||||||
|
let state_leaf_type =
|
||||||
|
CircuitType::from_input_section(&self, STATE_LEAF_VARIABLE_NAME.to_string(), state_leaf_values)?;
|
||||||
|
|
||||||
|
// Create a new `CircuitVariableType` for each type.
|
||||||
|
let registers_variable = CircuitVariableType::from(®isters_type);
|
||||||
|
let record_variable = CircuitVariableType::from(&record_type);
|
||||||
|
let state_variable = CircuitVariableType::from(&state_type);
|
||||||
|
let state_leaf_variable = CircuitVariableType::from(&state_leaf_type);
|
||||||
|
|
||||||
|
// Create new `CircuitType` for input keyword.
|
||||||
|
let input_type = CircuitType {
|
||||||
|
identifier: Identifier::new(INPUT_VARIABLE_NAME.to_string()),
|
||||||
|
variables: vec![registers_variable, record_variable, state_variable, state_leaf_variable],
|
||||||
|
functions: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert each circuit type into the symbol table.
|
||||||
|
self.insert_circuit_type(registers_type.identifier.clone(), registers_type);
|
||||||
|
self.insert_circuit_type(record_type.identifier.clone(), record_type);
|
||||||
|
self.insert_circuit_type(state_type.identifier.clone(), state_type);
|
||||||
|
self.insert_circuit_type(state_leaf_type.identifier.clone(), state_leaf_type);
|
||||||
|
self.insert_circuit_type(input_type.identifier.clone(), input_type);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
194
symbol-table/src/types/circuits/circuit.rs
Normal file
194
symbol-table/src/types/circuits/circuit.rs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// 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::{
|
||||||
|
types::circuits::{CircuitFunctionType, CircuitVariableType},
|
||||||
|
Attribute,
|
||||||
|
FunctionType,
|
||||||
|
SymbolTable,
|
||||||
|
Type,
|
||||||
|
TypeError,
|
||||||
|
};
|
||||||
|
use leo_ast::{Circuit, CircuitMember, Identifier, InputValue, Parameter, Span};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Stores circuit definition details.
|
||||||
|
///
|
||||||
|
/// This type should be added to the circuit symbol table for a resolved syntax tree.
|
||||||
|
/// This is a user-defined type.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct CircuitType {
|
||||||
|
/// The name of the circuit definition.
|
||||||
|
pub identifier: Identifier,
|
||||||
|
|
||||||
|
/// The circuit variables.
|
||||||
|
pub variables: Vec<CircuitVariableType>,
|
||||||
|
|
||||||
|
/// The circuit functions.
|
||||||
|
pub functions: Vec<CircuitFunctionType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CircuitType {
|
||||||
|
///
|
||||||
|
/// Return a new `CircuitType` from a given `Circuit` definition.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the circuit definition contains
|
||||||
|
/// user-defined types.
|
||||||
|
///
|
||||||
|
pub fn new(table: &SymbolTable, unresolved: Circuit) -> Result<Self, TypeError> {
|
||||||
|
let circuit_identifier = unresolved.circuit_name;
|
||||||
|
let mut variables = vec![];
|
||||||
|
let mut functions = vec![];
|
||||||
|
|
||||||
|
// Resolve the type of every circuit member.
|
||||||
|
for member in unresolved.members {
|
||||||
|
match member {
|
||||||
|
CircuitMember::CircuitVariable(is_mutable, variable_identifier, type_) => {
|
||||||
|
// Resolve the type of the circuit member variable.
|
||||||
|
let type_ = Type::new_from_circuit(
|
||||||
|
table,
|
||||||
|
type_,
|
||||||
|
circuit_identifier.clone(),
|
||||||
|
circuit_identifier.span.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Check if the circuit member variable is mutable.
|
||||||
|
let attribute = if is_mutable { Some(Attribute::Mutable) } else { None };
|
||||||
|
|
||||||
|
// Create a new circuit variable type.
|
||||||
|
let variable = CircuitVariableType {
|
||||||
|
identifier: variable_identifier,
|
||||||
|
type_,
|
||||||
|
attribute,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store the circuit variable type.
|
||||||
|
variables.push(variable);
|
||||||
|
}
|
||||||
|
CircuitMember::CircuitFunction(is_static, function) => {
|
||||||
|
// Resolve the type of the circuit member function.
|
||||||
|
let function_type = FunctionType::from_circuit(table, circuit_identifier.clone(), function)?;
|
||||||
|
|
||||||
|
// Check if the circuit member function is static.
|
||||||
|
let attribute = if is_static { Some(Attribute::Static) } else { None };
|
||||||
|
|
||||||
|
// Create a new circuit function type.
|
||||||
|
let function = CircuitFunctionType {
|
||||||
|
function: function_type,
|
||||||
|
attribute,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store the circuit function type.
|
||||||
|
functions.push(function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a new circuit type.
|
||||||
|
Ok(CircuitType {
|
||||||
|
identifier: circuit_identifier,
|
||||||
|
variables,
|
||||||
|
functions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the function type of a circuit member given an identifier.
|
||||||
|
///
|
||||||
|
pub fn member_function_type(&self, identifier: &Identifier) -> Option<&CircuitFunctionType> {
|
||||||
|
self.functions
|
||||||
|
.iter()
|
||||||
|
.find(|function| function.function.identifier.eq(identifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the type of a circuit member.
|
||||||
|
///
|
||||||
|
/// If the member is a circuit variable, then the type of the variable is returned.
|
||||||
|
/// If the member is a circuit function, then the return type of the function is returned.
|
||||||
|
///
|
||||||
|
pub fn member_type(&self, identifier: &Identifier) -> Result<Type, TypeError> {
|
||||||
|
// Check if the circuit member is a circuit variable.
|
||||||
|
let matched_variable = self
|
||||||
|
.variables
|
||||||
|
.iter()
|
||||||
|
.find(|variable| variable.identifier.eq(identifier));
|
||||||
|
|
||||||
|
match matched_variable {
|
||||||
|
Some(variable) => Ok(variable.type_.to_owned()),
|
||||||
|
None => {
|
||||||
|
// Check if the circuit member is a circuit function.
|
||||||
|
let matched_function = self.member_function_type(identifier);
|
||||||
|
|
||||||
|
match matched_function {
|
||||||
|
Some(function) => Ok(Type::Function(function.function.identifier.to_owned())),
|
||||||
|
None => Err(TypeError::undefined_circuit_member(identifier.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a new `CircuitType` from a given `Input` struct.
|
||||||
|
///
|
||||||
|
pub fn from_input_section(
|
||||||
|
table: &SymbolTable,
|
||||||
|
name: String,
|
||||||
|
section: HashMap<Parameter, Option<InputValue>>,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
// Create a new `CircuitVariableType` for each section pair.
|
||||||
|
let mut variables = Vec::new();
|
||||||
|
|
||||||
|
for (parameter, _option) in section.into_iter() {
|
||||||
|
let variable = CircuitVariableType {
|
||||||
|
identifier: parameter.variable,
|
||||||
|
type_: Type::new(table, parameter.type_, Span::default())?,
|
||||||
|
attribute: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
variables.push(variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new `Identifier` for the input section.
|
||||||
|
let identifier = Identifier::new(name);
|
||||||
|
|
||||||
|
// Return a new `CircuitType` with the given name.
|
||||||
|
Ok(Self {
|
||||||
|
identifier,
|
||||||
|
variables,
|
||||||
|
functions: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for CircuitType {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.identifier.eq(&other.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for CircuitType {}
|
||||||
|
|
||||||
|
impl Hash for CircuitType {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.identifier.hash(state);
|
||||||
|
}
|
||||||
|
}
|
27
symbol-table/src/types/circuits/circuit_function.rs
Normal file
27
symbol-table/src/types/circuits/circuit_function.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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::{types::FunctionType, Attribute};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct CircuitFunctionType {
|
||||||
|
/// The function signature of the circuit function
|
||||||
|
pub function: FunctionType,
|
||||||
|
/// The attributes of the circuit function
|
||||||
|
pub attribute: Option<Attribute>,
|
||||||
|
}
|
40
symbol-table/src/types/circuits/circuit_variable.rs
Normal file
40
symbol-table/src/types/circuits/circuit_variable.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// 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::{Attribute, CircuitType, Type};
|
||||||
|
use leo_ast::Identifier;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct CircuitVariableType {
|
||||||
|
/// The name of the circuit variable
|
||||||
|
pub identifier: Identifier,
|
||||||
|
/// The type of the circuit variable
|
||||||
|
pub type_: Type,
|
||||||
|
/// The attribute of the circuit variable
|
||||||
|
pub attribute: Option<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&CircuitType> for CircuitVariableType {
|
||||||
|
fn from(type_: &CircuitType) -> Self {
|
||||||
|
Self {
|
||||||
|
identifier: type_.identifier.clone(),
|
||||||
|
type_: Type::Circuit(type_.identifier.clone()),
|
||||||
|
attribute: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
symbol-table/src/types/circuits/mod.rs
Normal file
24
symbol-table/src/types/circuits/mod.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod circuit;
|
||||||
|
pub use self::circuit::*;
|
||||||
|
|
||||||
|
pub mod circuit_function;
|
||||||
|
pub use self::circuit_function::*;
|
||||||
|
|
||||||
|
pub mod circuit_variable;
|
||||||
|
pub use self::circuit_variable::*;
|
136
symbol-table/src/types/functions/function.rs
Normal file
136
symbol-table/src/types/functions/function.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// 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::{
|
||||||
|
types::functions::{FunctionInputType, FunctionOutputType},
|
||||||
|
SymbolTable,
|
||||||
|
TypeError,
|
||||||
|
};
|
||||||
|
use leo_ast::{Function, Identifier};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
/// Stores function definition details.
|
||||||
|
///
|
||||||
|
/// This type should be added to the function symbol table for a resolved syntax tree.
|
||||||
|
/// This is a user-defined type.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct FunctionType {
|
||||||
|
/// The name of the function definition.
|
||||||
|
pub identifier: Identifier,
|
||||||
|
|
||||||
|
/// The function inputs.
|
||||||
|
pub inputs: Vec<FunctionInputType>,
|
||||||
|
|
||||||
|
/// The function output.
|
||||||
|
pub output: FunctionOutputType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionType {
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionType` from a given `Function` definition.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the function definition contains
|
||||||
|
/// user-defined types.
|
||||||
|
///
|
||||||
|
pub fn new(table: &SymbolTable, unresolved: Function) -> Result<Self, TypeError> {
|
||||||
|
let mut inputs_resolved = Vec::with_capacity(unresolved.input.len());
|
||||||
|
|
||||||
|
// Type check function inputs
|
||||||
|
for input in unresolved.input {
|
||||||
|
let input = FunctionInputType::new(table, input)?;
|
||||||
|
inputs_resolved.push(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type check function output
|
||||||
|
let output = FunctionOutputType::new(table, unresolved.output, unresolved.span)?;
|
||||||
|
|
||||||
|
Ok(FunctionType {
|
||||||
|
identifier: unresolved.identifier,
|
||||||
|
inputs: inputs_resolved,
|
||||||
|
output,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionType` from a given `Function` definition.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the function definition contains
|
||||||
|
/// user-defined types.
|
||||||
|
///
|
||||||
|
/// If the function definition contains the `Self` keyword, then the given circuit identifier
|
||||||
|
/// is used as the type.
|
||||||
|
///
|
||||||
|
pub fn from_circuit(
|
||||||
|
table: &SymbolTable,
|
||||||
|
circuit_name: Identifier,
|
||||||
|
unresolved_function: Function,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
let function_identifier = unresolved_function.identifier;
|
||||||
|
let mut inputs = Vec::with_capacity(unresolved_function.input.len());
|
||||||
|
|
||||||
|
// Type check function inputs.
|
||||||
|
for unresolved_input in unresolved_function.input {
|
||||||
|
let input = FunctionInputType::new_from_circuit(table, unresolved_input, circuit_name.clone())?;
|
||||||
|
inputs.push(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type check function output.
|
||||||
|
let output = FunctionOutputType::new_from_circuit(
|
||||||
|
table,
|
||||||
|
circuit_name,
|
||||||
|
unresolved_function.output,
|
||||||
|
unresolved_function.span,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(FunctionType {
|
||||||
|
identifier: function_identifier,
|
||||||
|
inputs,
|
||||||
|
output,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Resolve a function definition and insert it into the given symbol table.
|
||||||
|
///
|
||||||
|
pub fn insert_definition(table: &mut SymbolTable, unresolved_function: Function) -> Result<(), TypeError> {
|
||||||
|
// Get the identifier of the function.
|
||||||
|
let function_identifier = unresolved_function.identifier.clone();
|
||||||
|
|
||||||
|
// Resolve the function definition into a function type.
|
||||||
|
let function = Self::new(table, unresolved_function)?;
|
||||||
|
|
||||||
|
// Insert (function_identifier -> function_type) as a (key -> value) pair in the symbol table.
|
||||||
|
table.insert_function_type(function_identifier, function);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for FunctionType {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.identifier.eq(&other.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for FunctionType {}
|
||||||
|
|
||||||
|
impl Hash for FunctionType {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.identifier.hash(state);
|
||||||
|
}
|
||||||
|
}
|
100
symbol-table/src/types/functions/function_input.rs
Normal file
100
symbol-table/src/types/functions/function_input.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// 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::{FunctionInputVariableType, SymbolTable, Type, TypeError};
|
||||||
|
use leo_ast::{FunctionInput, Identifier, Span};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum FunctionInputType {
|
||||||
|
InputKeyword(Identifier),
|
||||||
|
Variable(FunctionInputVariableType),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionInputType {
|
||||||
|
///
|
||||||
|
/// Return the `Identifier` containing name and span information about the current function input.
|
||||||
|
///
|
||||||
|
pub fn identifier(&self) -> &Identifier {
|
||||||
|
match self {
|
||||||
|
FunctionInputType::InputKeyword(identifier) => identifier,
|
||||||
|
FunctionInputType::Variable(variable) => &variable.identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return the `Type` of the current function input.
|
||||||
|
///
|
||||||
|
pub fn type_(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
FunctionInputType::InputKeyword(identifier) => Type::Circuit(identifier.to_owned()),
|
||||||
|
FunctionInputType::Variable(variable) => variable.type_.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return the `Span` of the current function input.
|
||||||
|
///
|
||||||
|
pub fn span(&self) -> &Span {
|
||||||
|
match self {
|
||||||
|
FunctionInputType::InputKeyword(identifier) => &identifier.span,
|
||||||
|
FunctionInputType::Variable(variable) => &variable.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionInputType` from a given `FunctionInput`.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the function input contains
|
||||||
|
/// user-defined types.
|
||||||
|
///
|
||||||
|
pub fn new(table: &SymbolTable, unresolved: FunctionInput) -> Result<Self, TypeError> {
|
||||||
|
Ok(match unresolved {
|
||||||
|
FunctionInput::InputKeyword(identifier) => FunctionInputType::InputKeyword(identifier),
|
||||||
|
FunctionInput::Variable(variable) => {
|
||||||
|
let variable_resolved = FunctionInputVariableType::new(table, variable)?;
|
||||||
|
|
||||||
|
FunctionInputType::Variable(variable_resolved)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionInputType` from a given `FunctionInput`.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the function input contains
|
||||||
|
/// user-defined types.
|
||||||
|
///
|
||||||
|
/// If the type of the function input is the `Self` keyword, then the given circuit identifier
|
||||||
|
/// is used as the type.
|
||||||
|
///
|
||||||
|
pub fn new_from_circuit(
|
||||||
|
table: &SymbolTable,
|
||||||
|
unresolved: FunctionInput,
|
||||||
|
circuit_name: Identifier,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
Ok(match unresolved {
|
||||||
|
FunctionInput::InputKeyword(identifier) => FunctionInputType::InputKeyword(identifier),
|
||||||
|
FunctionInput::Variable(unresolved_function_input) => {
|
||||||
|
let function_input =
|
||||||
|
FunctionInputVariableType::new_from_circuit(table, unresolved_function_input, circuit_name)?;
|
||||||
|
|
||||||
|
FunctionInputType::Variable(function_input)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
107
symbol-table/src/types/functions/function_input_variable.rs
Normal file
107
symbol-table/src/types/functions/function_input_variable.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// 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::{Attribute, SymbolTable, Type, TypeError};
|
||||||
|
use leo_ast::{FunctionInputVariable, Identifier, Span};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct FunctionInputVariableType {
|
||||||
|
/// Name of function input.
|
||||||
|
pub identifier: Identifier,
|
||||||
|
|
||||||
|
/// Type of function input.
|
||||||
|
pub type_: Type,
|
||||||
|
|
||||||
|
/// The attributes of the function input.
|
||||||
|
pub attribute: Option<Attribute>,
|
||||||
|
|
||||||
|
/// The span of the function input.
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionInputVariableType {
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionInputVariableType` from a given `FunctionInputVariable`.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the type is user-defined.
|
||||||
|
///
|
||||||
|
pub fn new(table: &SymbolTable, unresolved: FunctionInputVariable) -> Result<Self, TypeError> {
|
||||||
|
let type_ = Type::new(table, unresolved.type_, unresolved.span.clone())?;
|
||||||
|
let attribute = if unresolved.mutable {
|
||||||
|
Some(Attribute::Mutable)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(FunctionInputVariableType {
|
||||||
|
identifier: unresolved.identifier,
|
||||||
|
type_,
|
||||||
|
attribute,
|
||||||
|
span: unresolved.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionInputVariableType` from a given `FunctionInputVariable`.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the type is user-defined.
|
||||||
|
///
|
||||||
|
/// If the type of the function return type is the `Self` keyword, then the given circuit
|
||||||
|
/// identifier is used as the type.
|
||||||
|
///
|
||||||
|
pub fn new_from_circuit(
|
||||||
|
table: &SymbolTable,
|
||||||
|
unresolved_function_input: FunctionInputVariable,
|
||||||
|
circuit_name: Identifier,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
let type_ = Type::new_from_circuit(
|
||||||
|
table,
|
||||||
|
unresolved_function_input.type_,
|
||||||
|
circuit_name,
|
||||||
|
unresolved_function_input.span.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let attribute = if unresolved_function_input.mutable {
|
||||||
|
Some(Attribute::Mutable)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(FunctionInputVariableType {
|
||||||
|
identifier: unresolved_function_input.identifier,
|
||||||
|
type_,
|
||||||
|
attribute,
|
||||||
|
span: unresolved_function_input.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for FunctionInputVariableType {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.identifier.eq(&other.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for FunctionInputVariableType {}
|
||||||
|
|
||||||
|
impl Hash for FunctionInputVariableType {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.identifier.hash(state)
|
||||||
|
}
|
||||||
|
}
|
69
symbol-table/src/types/functions/function_output.rs
Normal file
69
symbol-table/src/types/functions/function_output.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// 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::{SymbolTable, Type, TypeError};
|
||||||
|
|
||||||
|
use leo_ast::{Identifier, Span, Type as UnresolvedType};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct FunctionOutputType {
|
||||||
|
/// Type of function output.
|
||||||
|
pub type_: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionOutputType {
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionOutputType` from a given optional function return type and span.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the return type is user-defined.
|
||||||
|
///
|
||||||
|
pub(crate) fn new(
|
||||||
|
table: &SymbolTable,
|
||||||
|
function_output: Option<UnresolvedType>,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
let type_ = match function_output {
|
||||||
|
None => Type::Tuple(vec![]), // functions with no return value return an empty tuple
|
||||||
|
Some(type_) => Type::new(table, type_, span)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(FunctionOutputType { type_ })
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new `FunctionOutputType` from a given optional function return type and span.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the return type is user-defined.
|
||||||
|
///
|
||||||
|
/// If the type of the function return type is the `Self` keyword, then the given circuit
|
||||||
|
/// identifier is used as the type.
|
||||||
|
///
|
||||||
|
pub fn new_from_circuit(
|
||||||
|
table: &SymbolTable,
|
||||||
|
circuit_name: Identifier,
|
||||||
|
unresolved: Option<UnresolvedType>,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
let output_type = match unresolved {
|
||||||
|
None => Type::Tuple(vec![]),
|
||||||
|
Some(type_) => Type::new_from_circuit(table, type_, circuit_name, span)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(FunctionOutputType { type_: output_type })
|
||||||
|
}
|
||||||
|
}
|
27
symbol-table/src/types/functions/mod.rs
Normal file
27
symbol-table/src/types/functions/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod function;
|
||||||
|
pub use self::function::*;
|
||||||
|
|
||||||
|
pub mod function_input;
|
||||||
|
pub use self::function_input::*;
|
||||||
|
|
||||||
|
pub mod function_input_variable;
|
||||||
|
pub use self::function_input_variable::*;
|
||||||
|
|
||||||
|
pub mod function_output;
|
||||||
|
pub use self::function_output::*;
|
30
symbol-table/src/types/mod.rs
Normal file
30
symbol-table/src/types/mod.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod circuits;
|
||||||
|
pub use self::circuits::*;
|
||||||
|
|
||||||
|
pub mod functions;
|
||||||
|
pub use self::functions::*;
|
||||||
|
|
||||||
|
pub mod type_;
|
||||||
|
pub use self::type_::*;
|
||||||
|
|
||||||
|
pub mod type_variable;
|
||||||
|
pub use self::type_variable::*;
|
||||||
|
|
||||||
|
pub mod user_defined;
|
||||||
|
pub use self::user_defined::*;
|
265
symbol-table/src/types/type_.rs
Normal file
265
symbol-table/src/types/type_.rs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
// 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::{SymbolTable, TypeError, TypeVariable};
|
||||||
|
use leo_ast::{Identifier, IntegerType, Span, Type as UnresolvedType};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
cmp::{Eq, PartialEq},
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A type in a Leo program.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Type {
|
||||||
|
// Data types
|
||||||
|
Address,
|
||||||
|
Boolean,
|
||||||
|
Field,
|
||||||
|
Group,
|
||||||
|
IntegerType(IntegerType),
|
||||||
|
|
||||||
|
// Data type wrappers
|
||||||
|
Array(Box<Type>),
|
||||||
|
Tuple(Vec<Type>),
|
||||||
|
|
||||||
|
// User defined types
|
||||||
|
Circuit(Identifier),
|
||||||
|
Function(Identifier),
|
||||||
|
|
||||||
|
// Unknown type variables
|
||||||
|
TypeVariable(TypeVariable),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
///
|
||||||
|
/// Return a new type from the given unresolved type.
|
||||||
|
///
|
||||||
|
/// Performs a lookup in the given symbol table if the type is user-defined.
|
||||||
|
///
|
||||||
|
pub fn new(table: &SymbolTable, type_: UnresolvedType, span: Span) -> Result<Self, TypeError> {
|
||||||
|
Ok(match type_ {
|
||||||
|
UnresolvedType::Address => Type::Address,
|
||||||
|
UnresolvedType::Boolean => Type::Boolean,
|
||||||
|
UnresolvedType::Field => Type::Field,
|
||||||
|
UnresolvedType::Group => Type::Group,
|
||||||
|
UnresolvedType::IntegerType(integer) => Type::IntegerType(integer),
|
||||||
|
|
||||||
|
UnresolvedType::Array(type_, _) => {
|
||||||
|
let array_type = Type::new(table, *type_, span)?;
|
||||||
|
|
||||||
|
Type::Array(Box::new(array_type))
|
||||||
|
}
|
||||||
|
UnresolvedType::Tuple(types) => {
|
||||||
|
let tuple_types = types
|
||||||
|
.into_iter()
|
||||||
|
.map(|type_| Type::new(table, type_, span.clone()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Type::Tuple(tuple_types)
|
||||||
|
}
|
||||||
|
|
||||||
|
UnresolvedType::Circuit(identifier) => {
|
||||||
|
// Lookup the circuit type in the symbol table
|
||||||
|
let circuit_type = table
|
||||||
|
.get_circuit_type(&identifier.name)
|
||||||
|
.ok_or_else(|| TypeError::undefined_circuit(identifier))?;
|
||||||
|
|
||||||
|
Type::Circuit(circuit_type.identifier.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
UnresolvedType::SelfType => {
|
||||||
|
// Throw an error for using `Self` outside of a circuit
|
||||||
|
return Err(TypeError::self_not_available(span));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new type from the given unresolved type.
|
||||||
|
///
|
||||||
|
/// If this type is SelfType, return the circuit's type.
|
||||||
|
///
|
||||||
|
pub fn new_from_circuit(
|
||||||
|
table: &SymbolTable,
|
||||||
|
type_: UnresolvedType,
|
||||||
|
circuit_name: Identifier,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Self, TypeError> {
|
||||||
|
Ok(match type_ {
|
||||||
|
UnresolvedType::Array(type_, _) => {
|
||||||
|
let array_type = Type::new_from_circuit(table, *type_, circuit_name, span)?;
|
||||||
|
Type::Array(Box::new(array_type))
|
||||||
|
}
|
||||||
|
UnresolvedType::Tuple(types) => {
|
||||||
|
let tuple_types = types
|
||||||
|
.into_iter()
|
||||||
|
.map(|type_| Type::new_from_circuit(table, type_, circuit_name.clone(), span.clone()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Type::Tuple(tuple_types)
|
||||||
|
}
|
||||||
|
UnresolvedType::SelfType => Type::Circuit(circuit_name),
|
||||||
|
// The unresolved type does not depend on the current circuit definition
|
||||||
|
unresolved => Type::new(table, unresolved, span)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of signed integer types.
|
||||||
|
pub const fn signed_integer_types() -> [Type; 5] {
|
||||||
|
[
|
||||||
|
Type::IntegerType(IntegerType::I8),
|
||||||
|
Type::IntegerType(IntegerType::I16),
|
||||||
|
Type::IntegerType(IntegerType::I32),
|
||||||
|
Type::IntegerType(IntegerType::I64),
|
||||||
|
Type::IntegerType(IntegerType::I128),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of unsigned integer types.
|
||||||
|
pub const fn unsigned_integer_types() -> [Type; 5] {
|
||||||
|
[
|
||||||
|
Type::IntegerType(IntegerType::U8),
|
||||||
|
Type::IntegerType(IntegerType::U16),
|
||||||
|
Type::IntegerType(IntegerType::U32),
|
||||||
|
Type::IntegerType(IntegerType::U64),
|
||||||
|
Type::IntegerType(IntegerType::U128),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of positive integer types.
|
||||||
|
pub fn negative_integer_types() -> Vec<Type> {
|
||||||
|
let field_group = [Type::Field, Type::Group];
|
||||||
|
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
types.extend_from_slice(&field_group);
|
||||||
|
types.extend_from_slice(&Self::signed_integer_types());
|
||||||
|
|
||||||
|
types
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of integer types.
|
||||||
|
pub fn integer_types() -> Vec<Type> {
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
types.extend_from_slice(&Self::unsigned_integer_types());
|
||||||
|
types.extend_from_slice(&Self::negative_integer_types());
|
||||||
|
|
||||||
|
types
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of possible index types (u8, u16, u32).
|
||||||
|
pub fn index_types() -> Vec<Type> {
|
||||||
|
let index_types = [
|
||||||
|
Type::IntegerType(IntegerType::U8),
|
||||||
|
Type::IntegerType(IntegerType::U16),
|
||||||
|
Type::IntegerType(IntegerType::U32),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
types.extend_from_slice(&index_types);
|
||||||
|
|
||||||
|
types
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Replaces self with the given type if self is equal to the given `TypeVariable`.
|
||||||
|
///
|
||||||
|
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||||
|
match self {
|
||||||
|
Type::TypeVariable(self_variable) => {
|
||||||
|
if self_variable == variable {
|
||||||
|
*self = type_.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Array(self_type) => {
|
||||||
|
self_type.substitute(variable, type_);
|
||||||
|
}
|
||||||
|
Type::Tuple(types) => types
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|tuple_type| tuple_type.substitute(variable, type_)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Type {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match &self {
|
||||||
|
Type::Address => write!(f, "address"),
|
||||||
|
Type::Boolean => write!(f, "bool"),
|
||||||
|
Type::Field => write!(f, "field"),
|
||||||
|
Type::Group => write!(f, "group"),
|
||||||
|
Type::IntegerType(integer_type) => write!(f, "{}", integer_type),
|
||||||
|
|
||||||
|
Type::Array(type_) => write!(f, "[{}]", *type_),
|
||||||
|
Type::Tuple(tuple) => {
|
||||||
|
let tuple_string = tuple.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
|
||||||
|
|
||||||
|
write!(f, "({})", tuple_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::Circuit(identifier) => write!(f, "circuit {}", identifier),
|
||||||
|
Type::Function(identifier) => write!(f, "function {}", identifier),
|
||||||
|
Type::TypeVariable(type_variable) => write!(f, "{}", type_variable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Type {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Type::Address, Type::Address) => true,
|
||||||
|
(Type::Boolean, Type::Boolean) => true,
|
||||||
|
(Type::Field, Type::Field) => true,
|
||||||
|
(Type::Group, Type::Group) => true,
|
||||||
|
(Type::IntegerType(integer_type1), Type::IntegerType(integer_type2)) => integer_type1.eq(integer_type2),
|
||||||
|
|
||||||
|
(Type::Array(array1), Type::Array(array2)) => {
|
||||||
|
// Get both array element types before comparison.
|
||||||
|
let array1_element = get_array_element_type(array1);
|
||||||
|
let array2_element = get_array_element_type(array2);
|
||||||
|
|
||||||
|
// Check that both arrays have the same element type.
|
||||||
|
array1_element.eq(array2_element)
|
||||||
|
}
|
||||||
|
|
||||||
|
(Type::Tuple(types1), Type::Tuple(types2)) => types1.eq(types2),
|
||||||
|
(Type::Circuit(identifier1), Type::Circuit(identifier2)) => identifier1.eq(identifier2),
|
||||||
|
(Type::Function(identifier1), Type::Function(identifier2)) => identifier1.eq(identifier2),
|
||||||
|
(Type::TypeVariable(variable1), Type::TypeVariable(variable2)) => variable1.eq(variable2),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Type {}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the data type of the array element.
|
||||||
|
///
|
||||||
|
/// If the given `type_` is an array, call `get_array_element_type()` on the array element type.
|
||||||
|
/// If the given `type_` is any other type, return the `type_`.
|
||||||
|
///
|
||||||
|
pub fn get_array_element_type(type_: &Type) -> &Type {
|
||||||
|
if let Type::Array(element_type) = type_ {
|
||||||
|
get_array_element_type(element_type)
|
||||||
|
} else {
|
||||||
|
type_
|
||||||
|
}
|
||||||
|
}
|
46
symbol-table/src/types/type_variable.rs
Normal file
46
symbol-table/src/types/type_variable.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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_ast::Identifier;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// An unknown type in a Leo program.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TypeVariable {
|
||||||
|
identifier: Identifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TypeVariable {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Identifier> for TypeVariable {
|
||||||
|
fn from(identifier: Identifier) -> Self {
|
||||||
|
Self { identifier }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare the type variable `Identifier` and `Span`.
|
||||||
|
impl PartialEq for TypeVariable {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.identifier.name.eq(&other.identifier.name) || self.identifier.span.eq(&other.identifier.span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TypeVariable {}
|
18
symbol-table/src/types/user_defined/mod.rs
Normal file
18
symbol-table/src/types/user_defined/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod user_defined_type;
|
||||||
|
pub use self::user_defined_type::*;
|
86
symbol-table/src/types/user_defined/user_defined_type.rs
Normal file
86
symbol-table/src/types/user_defined/user_defined_type.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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::{Attribute, FunctionInputVariableType, Type};
|
||||||
|
use leo_ast::{Circuit, Function, Identifier};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Stores information for a user defined type.
|
||||||
|
///
|
||||||
|
/// User defined types include circuits and functions in a Leo program.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UserDefinedType {
|
||||||
|
pub identifier: Identifier,
|
||||||
|
pub type_: Type,
|
||||||
|
pub attribute: Option<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Circuit> for UserDefinedType {
|
||||||
|
fn from(value: Circuit) -> Self {
|
||||||
|
let identifier = value.circuit_name;
|
||||||
|
|
||||||
|
UserDefinedType {
|
||||||
|
identifier: identifier.clone(),
|
||||||
|
type_: Type::Circuit(identifier),
|
||||||
|
attribute: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Function> for UserDefinedType {
|
||||||
|
fn from(value: Function) -> Self {
|
||||||
|
let identifier = value.identifier;
|
||||||
|
|
||||||
|
UserDefinedType {
|
||||||
|
identifier: identifier.clone(),
|
||||||
|
type_: Type::Function(identifier),
|
||||||
|
attribute: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FunctionInputVariableType> for UserDefinedType {
|
||||||
|
fn from(value: FunctionInputVariableType) -> Self {
|
||||||
|
UserDefinedType {
|
||||||
|
identifier: value.identifier,
|
||||||
|
type_: value.type_,
|
||||||
|
attribute: value.attribute,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UserDefinedType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for UserDefinedType {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.identifier.eq(&other.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for UserDefinedType {}
|
||||||
|
|
||||||
|
impl Hash for UserDefinedType {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.identifier.hash(state);
|
||||||
|
}
|
||||||
|
}
|
122
symbol-table/tests/mod.rs
Normal file
122
symbol-table/tests/mod.rs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod symbol_table;
|
||||||
|
|
||||||
|
use leo_ast::{Ast, Input};
|
||||||
|
use leo_grammar::Grammar;
|
||||||
|
use leo_symbol_table::{SymbolTable, SymbolTableError};
|
||||||
|
|
||||||
|
use leo_imports::ImportParser;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const TEST_PROGRAM_PATH: &str = "";
|
||||||
|
|
||||||
|
/// A helper struct to test a `SymbolTable`.
|
||||||
|
pub struct TestSymbolTable {
|
||||||
|
ast: Ast,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSymbolTable {
|
||||||
|
///
|
||||||
|
/// Returns a Leo syntax tree given a Leo program.
|
||||||
|
///
|
||||||
|
pub fn new(bytes: &[u8]) -> Self {
|
||||||
|
// Get file string from bytes.
|
||||||
|
let file_string = String::from_utf8_lossy(bytes);
|
||||||
|
|
||||||
|
// Get test file path.
|
||||||
|
let file_path = PathBuf::from(TEST_PROGRAM_PATH);
|
||||||
|
|
||||||
|
// Get parser syntax tree.
|
||||||
|
let grammar = Grammar::new(&file_path, &*file_string).unwrap();
|
||||||
|
|
||||||
|
// Get Leo syntax tree.
|
||||||
|
let ast = Ast::new(TEST_PROGRAM_PATH, &grammar);
|
||||||
|
|
||||||
|
Self { ast }
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Parse the Leo syntax tree into a symbol table.
|
||||||
|
///
|
||||||
|
/// Expect no errors during parsing.
|
||||||
|
///
|
||||||
|
pub fn expect_success(self) {
|
||||||
|
// Get program.
|
||||||
|
let program = self.ast.into_repr();
|
||||||
|
|
||||||
|
// Create empty import parser.
|
||||||
|
let import_parser = ImportParser::default();
|
||||||
|
|
||||||
|
// Create empty input.
|
||||||
|
let input = Input::new();
|
||||||
|
|
||||||
|
// Create new symbol table.
|
||||||
|
let _symbol_table = SymbolTable::new(&program, &import_parser, &input).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Parse the Leo syntax tree into a symbol table.
|
||||||
|
///
|
||||||
|
/// Expect an error involving entries in the symbol table.
|
||||||
|
///
|
||||||
|
pub fn expect_pass_one_error(self) {
|
||||||
|
// Get program.
|
||||||
|
let program = self.ast.into_repr();
|
||||||
|
|
||||||
|
// Create new symbol table.
|
||||||
|
let static_check = &mut SymbolTable::default();
|
||||||
|
|
||||||
|
// Create empty import parser.
|
||||||
|
let import_parser = ImportParser::default();
|
||||||
|
|
||||||
|
// Run pass one and expect an error.
|
||||||
|
let error = static_check.check_names(&program, &import_parser).unwrap_err();
|
||||||
|
|
||||||
|
match error {
|
||||||
|
SymbolTableError::Error(_) => {} // Ok
|
||||||
|
error => panic!("Expected a symbol table error found `{}`", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Parse the Leo syntax tree into a symbol table.
|
||||||
|
///
|
||||||
|
/// Expect an error involving types in the symbol table.
|
||||||
|
///
|
||||||
|
pub fn expect_pass_two_error(self) {
|
||||||
|
// Get program.
|
||||||
|
let program = self.ast.into_repr();
|
||||||
|
|
||||||
|
// Create a new symbol table.
|
||||||
|
let static_check = &mut SymbolTable::default();
|
||||||
|
|
||||||
|
// Create empty import parser.
|
||||||
|
let import_parser = ImportParser::default();
|
||||||
|
|
||||||
|
// Run the pass one and expect no errors.
|
||||||
|
static_check.check_names(&program, &import_parser).unwrap();
|
||||||
|
|
||||||
|
// Run the pass two and expect and error.
|
||||||
|
let error = static_check.check_types(&program).unwrap_err();
|
||||||
|
|
||||||
|
match error {
|
||||||
|
SymbolTableError::TypeError(_) => {} //Ok
|
||||||
|
error => panic!("Expected a type error found `{}`", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
symbol-table/tests/symbol_table/duplicate_circuit.leo
Normal file
10
symbol-table/tests/symbol_table/duplicate_circuit.leo
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
///
|
||||||
|
/// Defines a circuit `Foo {}`.
|
||||||
|
/// Attempts to define a second circuit `Foo {}`.
|
||||||
|
///
|
||||||
|
/// Expected output: SymbolTableError
|
||||||
|
/// Message: "Duplicate circuit definition found for `Foo`."
|
||||||
|
///
|
||||||
|
|
||||||
|
circuit Foo {}
|
||||||
|
circuit Foo {}
|
10
symbol-table/tests/symbol_table/duplicate_function.leo
Normal file
10
symbol-table/tests/symbol_table/duplicate_function.leo
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
///
|
||||||
|
/// Defines a function `main() {}`.
|
||||||
|
/// Attempts to define a second function `main() {}`.
|
||||||
|
///
|
||||||
|
/// Expected output: SymbolTableError
|
||||||
|
/// Message: "Duplicate function definition found for `main`."
|
||||||
|
///
|
||||||
|
|
||||||
|
function main() {}
|
||||||
|
function main() {}
|
75
symbol-table/tests/symbol_table/mod.rs
Normal file
75
symbol-table/tests/symbol_table/mod.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// 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::TestSymbolTable;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Defines a circuit `Foo {}`.
|
||||||
|
/// Attempts to define a second circuit `Foo {}`.
|
||||||
|
///
|
||||||
|
/// Expected output: SymbolTableError
|
||||||
|
/// Message: "Duplicate circuit definition found for `Foo`."
|
||||||
|
///
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_circuit() {
|
||||||
|
let program_bytes = include_bytes!("duplicate_circuit.leo");
|
||||||
|
let resolver = TestSymbolTable::new(program_bytes);
|
||||||
|
|
||||||
|
resolver.expect_pass_one_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Defines a function `main() {}`.
|
||||||
|
/// Attempts to define a second function `main() {}`.
|
||||||
|
///
|
||||||
|
/// Expected output: SymbolTableError
|
||||||
|
/// Message: "Duplicate function definition found for `main`."
|
||||||
|
///
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_function() {
|
||||||
|
let program_bytes = include_bytes!("duplicate_function.leo");
|
||||||
|
let resolver = TestSymbolTable::new(program_bytes);
|
||||||
|
|
||||||
|
resolver.expect_pass_one_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Defines a function that returns `Self`.
|
||||||
|
///
|
||||||
|
/// Expected output: TypeError
|
||||||
|
/// Message: "Type `Self` is only available in circuit definitions and circuit functions."
|
||||||
|
///
|
||||||
|
#[test]
|
||||||
|
fn test_self_not_available() {
|
||||||
|
let program_bytes = include_bytes!("self_not_available.leo");
|
||||||
|
let resolver = TestSymbolTable::new(program_bytes);
|
||||||
|
|
||||||
|
resolver.expect_pass_two_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Defines a circuit with variable whose type is `Bar`, an undefined circuit.
|
||||||
|
///
|
||||||
|
/// Expected output: TypeError
|
||||||
|
/// Message: "Type circuit `Bar` must be defined before it is used in an expression."
|
||||||
|
///
|
||||||
|
#[test]
|
||||||
|
fn test_undefined_circuit() {
|
||||||
|
let program_bytes = include_bytes!("undefined_circuit.leo");
|
||||||
|
let resolver = TestSymbolTable::new(program_bytes);
|
||||||
|
|
||||||
|
resolver.expect_pass_two_error();
|
||||||
|
}
|
8
symbol-table/tests/symbol_table/self_not_available.leo
Normal file
8
symbol-table/tests/symbol_table/self_not_available.leo
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
///
|
||||||
|
/// Defines a function that returns `Self`.
|
||||||
|
///
|
||||||
|
/// Expected output: TypeError
|
||||||
|
/// Message: "Type `Self` is only available in circuit definitions and circuit functions."
|
||||||
|
///
|
||||||
|
|
||||||
|
function main() -> Self {}
|
10
symbol-table/tests/symbol_table/undefined_circuit.leo
Normal file
10
symbol-table/tests/symbol_table/undefined_circuit.leo
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
///
|
||||||
|
/// Defines a circuit with variable whose type is `Bar`, an undefined circuit.
|
||||||
|
///
|
||||||
|
/// Expected output: TypeError
|
||||||
|
/// Message: "Type circuit `Bar` must be defined before it is used in an expression."
|
||||||
|
///
|
||||||
|
|
||||||
|
circuit Foo {
|
||||||
|
b: Bar
|
||||||
|
}
|
43
type-inference/Cargo.toml
Normal file
43
type-inference/Cargo.toml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[package]
|
||||||
|
name = "leo-type-inference"
|
||||||
|
version = "1.0.4"
|
||||||
|
authors = [ "The Aleo Team <hello@aleo.org>" ]
|
||||||
|
description = "Checks that a program is correct using type inference"
|
||||||
|
homepage = "https://aleo.org"
|
||||||
|
repository = "https://github.com/AleoHQ/leo"
|
||||||
|
keywords = [
|
||||||
|
"aleo",
|
||||||
|
"cryptography",
|
||||||
|
"leo",
|
||||||
|
"programming-language",
|
||||||
|
"zero-knowledge"
|
||||||
|
]
|
||||||
|
categories = [ "cryptography::croptocurrencies", "web-programming" ]
|
||||||
|
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies.leo-ast]
|
||||||
|
path = "../ast"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-imports]
|
||||||
|
path = "../imports"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-grammar]
|
||||||
|
path = "../grammar"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.leo-symbol-table]
|
||||||
|
path = "../symbol-table"
|
||||||
|
version = "1.0.4"
|
||||||
|
|
||||||
|
[dependencies.serde_json]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.thiserror]
|
||||||
|
version = "1.0"
|
27
type-inference/src/assertions/mod.rs
Normal file
27
type-inference/src/assertions/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod type_assertion;
|
||||||
|
pub use self::type_assertion::*;
|
||||||
|
|
||||||
|
pub mod type_equality;
|
||||||
|
pub use self::type_equality::*;
|
||||||
|
|
||||||
|
pub mod type_membership;
|
||||||
|
pub use self::type_membership::*;
|
||||||
|
|
||||||
|
pub mod type_variable_pair;
|
||||||
|
pub use self::type_variable_pair::*;
|
74
type-inference/src/assertions/type_assertion.rs
Normal file
74
type-inference/src/assertions/type_assertion.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// 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::{TypeAssertionError, TypeEquality, TypeMembership, TypeVariablePairs};
|
||||||
|
use leo_ast::Span;
|
||||||
|
use leo_symbol_table::{Type, TypeVariable};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A predicate that evaluates equality between two `Types`s.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum TypeAssertion {
|
||||||
|
Equality(TypeEquality),
|
||||||
|
Membership(TypeMembership),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeAssertion {
|
||||||
|
///
|
||||||
|
/// Returns a `TypeAssertion::Equality` predicate from given left and right `Types`s.
|
||||||
|
///
|
||||||
|
pub fn new_equality(left: Type, right: Type, span: &Span) -> Self {
|
||||||
|
Self::Equality(TypeEquality::new(left, right, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `TypeAssertion::Membership` predicate from given and set `Type`s.
|
||||||
|
///
|
||||||
|
pub fn new_membership(given: Type, set: Vec<Type>, span: &Span) -> Self {
|
||||||
|
Self::Membership(TypeMembership::new(given, set, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns one or more `TypeVariablePairs` generated by the given `TypeAssertion`.
|
||||||
|
///
|
||||||
|
pub fn pairs(&self) -> Result<TypeVariablePairs, TypeAssertionError> {
|
||||||
|
match self {
|
||||||
|
TypeAssertion::Equality(equality) => equality.pairs(),
|
||||||
|
TypeAssertion::Membership(membership) => Err(TypeAssertionError::membership_pairs(membership)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Substitutes the given type for self if self is equal to the type variable.
|
||||||
|
///
|
||||||
|
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||||
|
match self {
|
||||||
|
TypeAssertion::Equality(equality) => equality.substitute(variable, type_),
|
||||||
|
TypeAssertion::Membership(membership) => membership.substitute(variable, type_),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks if the `TypeAssertion` is satisfied.
|
||||||
|
///
|
||||||
|
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||||
|
match self {
|
||||||
|
TypeAssertion::Equality(equality) => equality.evaluate(),
|
||||||
|
TypeAssertion::Membership(membership) => membership.evaluate(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
type-inference/src/assertions/type_equality.rs
Normal file
68
type-inference/src/assertions/type_equality.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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::{TypeAssertionError, TypeVariablePairs};
|
||||||
|
use leo_ast::Span;
|
||||||
|
use leo_symbol_table::{Type, TypeVariable};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A predicate that evaluates equality between two `Type`s.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TypeEquality {
|
||||||
|
left: Type,
|
||||||
|
right: Type,
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeEquality {
|
||||||
|
///
|
||||||
|
/// Returns a `TypeEquality` predicate from given left and right `Types`s
|
||||||
|
///
|
||||||
|
pub fn new(left: Type, right: Type, span: &Span) -> Self {
|
||||||
|
Self {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
span: span.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Substitutes the given `TypeVariable` for each `Types` in the `TypeEquality`.
|
||||||
|
///
|
||||||
|
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||||
|
self.left.substitute(variable, type_);
|
||||||
|
self.right.substitute(variable, type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks if the `self.left` == `self.right`.
|
||||||
|
///
|
||||||
|
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||||
|
if self.left.eq(&self.right) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(TypeAssertionError::equality_failed(&self.left, &self.right, &self.span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the (type variable, type) pair from this assertion.
|
||||||
|
///
|
||||||
|
pub fn pairs(&self) -> Result<TypeVariablePairs, TypeAssertionError> {
|
||||||
|
TypeVariablePairs::new(self.left.to_owned(), self.right.to_owned(), &self.span)
|
||||||
|
}
|
||||||
|
}
|
71
type-inference/src/assertions/type_membership.rs
Normal file
71
type-inference/src/assertions/type_membership.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// 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::TypeAssertionError;
|
||||||
|
use leo_ast::Span;
|
||||||
|
use leo_symbol_table::{Type, TypeVariable};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A predicate that evaluates to true if the given type is equal to a member in the set vector of types.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TypeMembership {
|
||||||
|
given: Type,
|
||||||
|
set: Vec<Type>,
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeMembership {
|
||||||
|
///
|
||||||
|
/// Returns a `TypeMembership` predicate from given and set `Type`s.
|
||||||
|
///
|
||||||
|
pub fn new(given: Type, set: Vec<Type>, span: &Span) -> Self {
|
||||||
|
Self {
|
||||||
|
given,
|
||||||
|
set,
|
||||||
|
span: span.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Substitutes the given `TypeVariable` for each `Type` in the `TypeMembership`.
|
||||||
|
///
|
||||||
|
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||||
|
self.given.substitute(variable, type_)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns true if the given type is equal to a member of the set.
|
||||||
|
///
|
||||||
|
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||||
|
if self.set.contains(&self.given) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(TypeAssertionError::membership_failed(
|
||||||
|
&self.given,
|
||||||
|
&self.set,
|
||||||
|
&self.span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the self.span.
|
||||||
|
///
|
||||||
|
pub fn span(&self) -> &Span {
|
||||||
|
&self.span
|
||||||
|
}
|
||||||
|
}
|
137
type-inference/src/assertions/type_variable_pair.rs
Normal file
137
type-inference/src/assertions/type_variable_pair.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// 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::TypeAssertionError;
|
||||||
|
use leo_ast::Span;
|
||||||
|
use leo_symbol_table::{get_array_element_type, Type, TypeVariable};
|
||||||
|
|
||||||
|
/// A type variable -> type pair.
|
||||||
|
pub struct TypeVariablePair(TypeVariable, Type);
|
||||||
|
|
||||||
|
impl TypeVariablePair {
|
||||||
|
pub fn first(&self) -> &TypeVariable {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn second(&self) -> &Type {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vector of `TypeVariablePair`s.
|
||||||
|
pub struct TypeVariablePairs(Vec<TypeVariablePair>);
|
||||||
|
|
||||||
|
impl Default for TypeVariablePairs {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeVariablePairs {
|
||||||
|
///
|
||||||
|
/// Returns a new `TypeVariablePairs` struct from the given left and right types.
|
||||||
|
///
|
||||||
|
pub fn new(left: Type, right: Type, span: &Span) -> Result<Self, TypeAssertionError> {
|
||||||
|
let mut pairs = Self::default();
|
||||||
|
|
||||||
|
// Push all `TypeVariablePair`s.
|
||||||
|
pairs.push_pairs(left, right, span)?;
|
||||||
|
|
||||||
|
Ok(pairs)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns true if the self vector has no pairs.
|
||||||
|
///
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the self vector of pairs.
|
||||||
|
///
|
||||||
|
pub fn get_pairs(&self) -> &[TypeVariablePair] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Pushes a new `TypeVariablePair` struct to self.
|
||||||
|
///
|
||||||
|
pub fn push(&mut self, variable: TypeVariable, type_: Type) {
|
||||||
|
// Create a new type variable -> type pair.
|
||||||
|
let pair = TypeVariablePair(variable, type_);
|
||||||
|
|
||||||
|
// Push the pair to the self vector.
|
||||||
|
self.0.push(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks if the given left or right type contains a `TypeVariable`.
|
||||||
|
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||||
|
/// and right type.
|
||||||
|
///
|
||||||
|
pub fn push_pairs(&mut self, left: Type, right: Type, span: &Span) -> Result<(), TypeAssertionError> {
|
||||||
|
match (left, right) {
|
||||||
|
(Type::TypeVariable(variable), type_) => {
|
||||||
|
self.push(variable, type_);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(type_, Type::TypeVariable(variable)) => {
|
||||||
|
self.push(variable, type_);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(Type::Array(left_type), Type::Array(right_type)) => self.push_pairs_array(*left_type, *right_type, span),
|
||||||
|
(Type::Tuple(left_types), Type::Tuple(right_types)) => {
|
||||||
|
self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span)
|
||||||
|
}
|
||||||
|
(_, _) => Ok(()), // No `TypeVariable` found so we do not push any pairs.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks if the given left or right array type contains a `TypeVariable`.
|
||||||
|
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||||
|
/// and right type.
|
||||||
|
///
|
||||||
|
fn push_pairs_array(&mut self, left_type: Type, right_type: Type, span: &Span) -> Result<(), TypeAssertionError> {
|
||||||
|
// Get both array element types before comparison.
|
||||||
|
let array1_element = get_array_element_type(&left_type);
|
||||||
|
let array2_element = get_array_element_type(&right_type);
|
||||||
|
|
||||||
|
// Compare the array element types.
|
||||||
|
self.push_pairs(array1_element.to_owned(), array2_element.to_owned(), span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks if any given left or right tuple type contains a `TypeVariable`.
|
||||||
|
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||||
|
/// and right type.
|
||||||
|
///
|
||||||
|
fn push_pairs_tuple(
|
||||||
|
&mut self,
|
||||||
|
left_types: impl Iterator<Item = Type>,
|
||||||
|
right_types: impl Iterator<Item = Type>,
|
||||||
|
span: &Span,
|
||||||
|
) -> Result<(), TypeAssertionError> {
|
||||||
|
// Iterate over each left == right pair of types.
|
||||||
|
for (left, right) in left_types.into_iter().zip(right_types) {
|
||||||
|
// Check for `TypeVariablePair`s.
|
||||||
|
self.push_pairs(left, right, span)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
240
type-inference/src/errors/frame.rs
Normal file
240
type-inference/src/errors/frame.rs
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
// 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::{ScopeError, TypeAssertionError};
|
||||||
|
use leo_ast::{Error as FormattedError, Expression, Identifier, Span};
|
||||||
|
use leo_symbol_table::{Type, TypeError};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when tracking variable names in a program.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum FrameError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
ScopeError(#[from] ScopeError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
TypeAssertionError(#[from] TypeAssertionError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
TypeError(#[from] TypeError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
FrameError::Error(error) => error.set_path(path),
|
||||||
|
FrameError::ScopeError(error) => error.set_path(path),
|
||||||
|
FrameError::TypeAssertionError(error) => error.set_path(path),
|
||||||
|
FrameError::TypeError(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new formatted error with a given message and span information
|
||||||
|
///
|
||||||
|
fn new_from_span(message: String, span: &Span) -> Self {
|
||||||
|
FrameError::Error(FormattedError::new_from_span(message, span.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to access the index of a non-array type.
|
||||||
|
///
|
||||||
|
pub fn array_access(actual: &Type, span: &Span) -> Self {
|
||||||
|
let message = format!("Cannot access the index of non-array type `{}`.", actual);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to access the `Self` type outside of a circuit context.
|
||||||
|
///
|
||||||
|
pub fn circuit_self(span: &Span) -> Self {
|
||||||
|
let message = "The `Self` keyword is only valid inside a circuit context.".to_string();
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Two variables have been defined with the same name.
|
||||||
|
///
|
||||||
|
pub fn duplicate_variable(name: &str, span: &Span) -> Self {
|
||||||
|
let message = format!("Duplicate variable definition found for `{}`", name);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to create an empty array in a Leo program.
|
||||||
|
///
|
||||||
|
/// Arrays in Leo are not resizeable so defining empty arrays are effectively dead code.
|
||||||
|
///
|
||||||
|
pub fn empty_array(span: &Span) -> Self {
|
||||||
|
let message = "Cannot create an empty array in a Leo program.".to_string();
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Expected a circuit name but found a different type.
|
||||||
|
///
|
||||||
|
pub fn invalid_circuit(type_: Type, span: &Span) -> Self {
|
||||||
|
let message = format!("Expected a circuit type. Found type `{}`.", type_);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Expected a function name but found a different expression.
|
||||||
|
///
|
||||||
|
pub fn invalid_function(expression: &Expression, span: &Span) -> Self {
|
||||||
|
let message = format!("Expected a function name. Found expression `{}`.", expression);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Expected a usize number for the index.
|
||||||
|
///
|
||||||
|
pub fn invalid_index(actual: String, span: &Span) -> Self {
|
||||||
|
let message = format!("Expected constant number for index, found `{}`", actual);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call non-static member using `::`.
|
||||||
|
///
|
||||||
|
pub fn invalid_member_access(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("non-static member `{}` must be accessed using `.` syntax.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to use the spread operator on a non-array type.
|
||||||
|
///
|
||||||
|
pub fn invalid_spread(actual: Type, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"The spread operator `...` can only be applied to array types. Found type `{}`.",
|
||||||
|
actual
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call static member using `.`.
|
||||||
|
///
|
||||||
|
pub fn invalid_static_access(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("Static member `{}` must be accessed using `::` syntax.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to create a circuit with the incorrect number of member variables.
|
||||||
|
///
|
||||||
|
pub fn num_circuit_variables(expected: usize, actual: usize, span: &Span) -> Self {
|
||||||
|
let message = format!("Circuit expected {} variables, found {} variables.", expected, actual);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call a function with the incorrect number of inputs.
|
||||||
|
///
|
||||||
|
pub fn num_inputs(expected: usize, actual: usize, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Function expected {} input variables, found {} inputs.",
|
||||||
|
expected, actual
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to access the index of a non-tuple type.
|
||||||
|
///
|
||||||
|
pub fn tuple_access(actual: &Type, span: &Span) -> Self {
|
||||||
|
let message = format!("Cannot access the index of non-tuple type `{}`.", actual);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call a circuit type that is not defined in the current context.
|
||||||
|
///
|
||||||
|
pub fn undefined_circuit(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("The circuit `{}` is not defined.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call a circuit function that is not defined in the current context.
|
||||||
|
///
|
||||||
|
pub fn undefined_circuit_function(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("The circuit function `{}` is not defined.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call a function that is not defined in the current context.
|
||||||
|
///
|
||||||
|
pub fn undefined_function(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("The function `{}` is not defined.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to call a variable that is not defined in the current context.
|
||||||
|
///
|
||||||
|
pub fn undefined_variable(identifier: &Identifier) -> Self {
|
||||||
|
let message = format!("The variable `{}` is not defined.", identifier);
|
||||||
|
|
||||||
|
Self::new_from_span(message, &identifier.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to assign a tuple of variables to a single value.
|
||||||
|
///
|
||||||
|
pub fn not_enough_values(span: &Span) -> Self {
|
||||||
|
let message = "Expected a tuple type for multiple defined variables".to_string();
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to assign a tuple with a different number of variables than values.
|
||||||
|
///
|
||||||
|
pub fn invalid_number_of_values(expected: usize, actual: usize, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Incorrect number of defined variables. Expected `{}`, found `{}`.",
|
||||||
|
expected, actual
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
}
|
30
type-inference/src/errors/mod.rs
Normal file
30
type-inference/src/errors/mod.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod frame;
|
||||||
|
pub use self::frame::*;
|
||||||
|
|
||||||
|
pub mod scope;
|
||||||
|
pub use self::scope::*;
|
||||||
|
|
||||||
|
pub mod type_assertion;
|
||||||
|
pub use self::type_assertion::*;
|
||||||
|
|
||||||
|
pub mod type_inference;
|
||||||
|
pub use self::type_inference::*;
|
||||||
|
|
||||||
|
pub mod variable_table;
|
||||||
|
pub use self::variable_table::*;
|
42
type-inference/src/errors/scope.rs
Normal file
42
type-inference/src/errors/scope.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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::VariableTableError;
|
||||||
|
use leo_ast::Error as FormattedError;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when evaluating variables in a scope.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ScopeError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
VariableTableError(#[from] VariableTableError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScopeError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace.
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
ScopeError::Error(error) => error.set_path(path),
|
||||||
|
ScopeError::VariableTableError(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
type-inference/src/errors/type_assertion.rs
Normal file
77
type-inference/src/errors/type_assertion.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// 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::TypeMembership;
|
||||||
|
|
||||||
|
use leo_ast::{Error as FormattedError, Span};
|
||||||
|
use leo_symbol_table::Type;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when attempting to solve a type assertion.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TypeAssertionError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeAssertionError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace.
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
TypeAssertionError::Error(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a new formatted error with a given message and span information.
|
||||||
|
///
|
||||||
|
fn new_from_span(message: String, span: &Span) -> Self {
|
||||||
|
TypeAssertionError::Error(FormattedError::new_from_span(message, span.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Found mismatched types during program parsing.
|
||||||
|
///
|
||||||
|
pub fn equality_failed(left: &Type, right: &Type, span: &Span) -> Self {
|
||||||
|
let message = format!("Mismatched types. Expected type `{}`, found type `{}`.", left, right);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Given type is not a member of the set of expected types.
|
||||||
|
///
|
||||||
|
pub fn membership_failed(given: &Type, set: &[Type], span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Mismatched types. Given type `{}` is not in the expected type set `{:?}`.",
|
||||||
|
given, set
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to generate pairs from a membership assertion.
|
||||||
|
///
|
||||||
|
pub fn membership_pairs(membership: &TypeMembership) -> Self {
|
||||||
|
let message = "Cannot generate a type variable -> type pair for the given type membership".to_string();
|
||||||
|
|
||||||
|
Self::new_from_span(message, membership.span())
|
||||||
|
}
|
||||||
|
}
|
42
type-inference/src/errors/type_inference.rs
Normal file
42
type-inference/src/errors/type_inference.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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::FrameError;
|
||||||
|
use leo_ast::Error as FormattedError;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when running type inference checks.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TypeInferenceError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
FrameError(#[from] FrameError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeInferenceError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace.
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
TypeInferenceError::Error(error) => error.set_path(path),
|
||||||
|
TypeInferenceError::FrameError(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
type-inference/src/errors/variable_table.rs
Normal file
53
type-inference/src/errors/variable_table.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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_ast::{Error as FormattedError, Span};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Errors encountered when tracking variable names in a program.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum VariableTableError {
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Error(#[from] FormattedError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableTableError {
|
||||||
|
///
|
||||||
|
/// Set the filepath for the error stacktrace
|
||||||
|
///
|
||||||
|
pub fn set_path(&mut self, path: &Path) {
|
||||||
|
match self {
|
||||||
|
VariableTableError::Error(error) => error.set_path(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return a new formatted error with a given message and span information
|
||||||
|
///
|
||||||
|
fn new_from_span(message: String, span: Span) -> Self {
|
||||||
|
VariableTableError::Error(FormattedError::new_from_span(message, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempted to define two function inputs with the same name.
|
||||||
|
///
|
||||||
|
pub fn duplicate_function_input(name: &str, span: &Span) -> Self {
|
||||||
|
let message = format!("Duplicate function input `{}`found in function signature.", name);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span.clone())
|
||||||
|
}
|
||||||
|
}
|
37
type-inference/src/lib.rs
Normal file
37
type-inference/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! A type inference check for a Leo program.
|
||||||
|
//!
|
||||||
|
//! This module contains the [`TypeInference`] type, which stores information needed to run a type
|
||||||
|
//! inference check over a program.
|
||||||
|
//!
|
||||||
|
//! A new [`TypeInference`] type can be created from a [`LeoAst`] type and a [`Symbol Table`].
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate thiserror;
|
||||||
|
|
||||||
|
pub mod assertions;
|
||||||
|
pub use self::assertions::*;
|
||||||
|
|
||||||
|
pub mod type_inference;
|
||||||
|
pub use self::type_inference::*;
|
||||||
|
|
||||||
|
pub mod errors;
|
||||||
|
pub use self::errors::*;
|
||||||
|
|
||||||
|
pub mod objects;
|
||||||
|
pub use self::objects::*;
|
1210
type-inference/src/objects/frame.rs
Normal file
1210
type-inference/src/objects/frame.rs
Normal file
File diff suppressed because it is too large
Load Diff
24
type-inference/src/objects/mod.rs
Normal file
24
type-inference/src/objects/mod.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod frame;
|
||||||
|
pub use self::frame::*;
|
||||||
|
|
||||||
|
pub mod scope;
|
||||||
|
pub use self::scope::*;
|
||||||
|
|
||||||
|
pub mod variable_table;
|
||||||
|
pub use self::variable_table::*;
|
81
type-inference/src/objects/scope.rs
Normal file
81
type-inference/src/objects/scope.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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::{ScopeError, VariableTable};
|
||||||
|
use leo_symbol_table::{FunctionInputType, Type};
|
||||||
|
|
||||||
|
/// A structure for tracking the types of defined variables in a block of code.
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Scope {
|
||||||
|
pub loop_variables: VariableTable,
|
||||||
|
pub variables: VariableTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
///
|
||||||
|
/// Returns a new `Scope` from an optional given `Scope`.
|
||||||
|
///
|
||||||
|
/// The new scope will contain the variables of the optional given `Scope`.
|
||||||
|
///
|
||||||
|
pub fn new(parent: Option<Scope>) -> Self {
|
||||||
|
match parent {
|
||||||
|
Some(scope) => scope,
|
||||||
|
None => Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts a variable name -> type mapping into the loop variable table.
|
||||||
|
///
|
||||||
|
pub fn insert_loop_variable(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||||
|
self.loop_variables.insert(name, type_)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts a variable name -> type mapping into the variable table.
|
||||||
|
///
|
||||||
|
pub fn insert_variable(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||||
|
self.variables.insert(name, type_)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the type corresponding to the loop variable name.
|
||||||
|
///
|
||||||
|
pub fn get_loop_variable(&self, name: &str) -> Option<&Type> {
|
||||||
|
self.loop_variables.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the type corresponding to the variable name.
|
||||||
|
///
|
||||||
|
/// Checks loop variables first, then non-loop variables.
|
||||||
|
///
|
||||||
|
pub fn get_variable(&self, name: &str) -> Option<&Type> {
|
||||||
|
match self.get_loop_variable(name) {
|
||||||
|
Some(loop_variable_type) => Some(loop_variable_type),
|
||||||
|
None => self.variables.get(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts a vector of function input types into the `Scope` variable table.
|
||||||
|
///
|
||||||
|
pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), ScopeError> {
|
||||||
|
self.variables
|
||||||
|
.insert_function_inputs(function_inputs)
|
||||||
|
.map_err(ScopeError::VariableTableError)
|
||||||
|
}
|
||||||
|
}
|
72
type-inference/src/objects/variable_table.rs
Normal file
72
type-inference/src/objects/variable_table.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// 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::VariableTableError;
|
||||||
|
use leo_symbol_table::{FunctionInputType, Type};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Mapping of variable names to types
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VariableTable(pub HashMap<String, Type>);
|
||||||
|
|
||||||
|
impl VariableTable {
|
||||||
|
///
|
||||||
|
/// Insert a name -> type pair into the variable table.
|
||||||
|
///
|
||||||
|
/// If the variable table did not have this key present, [`None`] is returned.
|
||||||
|
///
|
||||||
|
/// If the variable table did have this key present, the type is updated, and the old
|
||||||
|
/// type is returned.
|
||||||
|
///
|
||||||
|
pub fn insert(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||||
|
self.0.insert(name, type_)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the type corresponding to the name.
|
||||||
|
///
|
||||||
|
/// If the variable table did not have this key present, throw an undefined variable error
|
||||||
|
/// using the given span.
|
||||||
|
///
|
||||||
|
pub fn get(&self, name: &str) -> Option<&Type> {
|
||||||
|
self.0.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Inserts a vector of function input types into the variable table.
|
||||||
|
///
|
||||||
|
pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), VariableTableError> {
|
||||||
|
for input in function_inputs {
|
||||||
|
let input_name = &input.identifier().name;
|
||||||
|
let input_type = input.type_();
|
||||||
|
let input_span = input.span();
|
||||||
|
|
||||||
|
// Check for duplicate function input names.
|
||||||
|
let duplicate = self.insert(input_name.clone(), input_type);
|
||||||
|
|
||||||
|
if duplicate.is_some() {
|
||||||
|
return Err(VariableTableError::duplicate_function_input(input_name, input_span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VariableTable {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(HashMap::new())
|
||||||
|
}
|
||||||
|
}
|
138
type-inference/src/type_inference.rs
Normal file
138
type-inference/src/type_inference.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// 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::{Frame, Scope, TypeInferenceError};
|
||||||
|
use leo_ast::{Circuit, CircuitMember, Function, Program};
|
||||||
|
use leo_symbol_table::SymbolTable;
|
||||||
|
|
||||||
|
/// A type inference check for a Leo program.
|
||||||
|
///
|
||||||
|
/// A [`TypeInference`] type stores a stack of frames. A new frame is created for every
|
||||||
|
/// function. Frames store type assertions that assert an expression is a type.
|
||||||
|
/// Calling the `check()` method on a [`TypeInference`] checks that all type assertions are satisfied.
|
||||||
|
pub struct TypeInference {
|
||||||
|
table: SymbolTable,
|
||||||
|
frames: Vec<Frame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeInference {
|
||||||
|
///
|
||||||
|
/// Creates and runs a new `TypeInference` check on a given program and symbol table.
|
||||||
|
///
|
||||||
|
/// Evaluates all `TypeAssertion` predicates.
|
||||||
|
///
|
||||||
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
pub fn new(program: &Program, symbol_table: SymbolTable) -> Result<(), TypeInferenceError> {
|
||||||
|
let mut type_inference = Self {
|
||||||
|
table: symbol_table,
|
||||||
|
frames: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
type_inference.parse_program(program)?;
|
||||||
|
|
||||||
|
type_inference.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Collects a vector of `TypeAssertion` predicates from a program.
|
||||||
|
///
|
||||||
|
fn parse_program(&mut self, program: &Program) -> Result<(), TypeInferenceError> {
|
||||||
|
// Parse circuit types in program context.
|
||||||
|
self.parse_circuits(program.circuits.iter().map(|(_identifier, circuit)| circuit))?;
|
||||||
|
|
||||||
|
// Parse functions in program context.
|
||||||
|
self.parse_functions(program.functions.iter().map(|(_identifier, function)| function))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Collects a vector of `Frames`s from a vector of circuit functions.
|
||||||
|
///
|
||||||
|
fn parse_circuits<'a>(&mut self, circuits: impl Iterator<Item = &'a Circuit>) -> Result<(), TypeInferenceError> {
|
||||||
|
for circuit in circuits {
|
||||||
|
self.parse_circuit(circuit)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Collects a vector of `Frames`s from a circuit function.
|
||||||
|
///
|
||||||
|
/// Each frame collects a vector of `TypeAssertion` predicates from each function.
|
||||||
|
///
|
||||||
|
fn parse_circuit(&mut self, circuit: &Circuit) -> Result<(), TypeInferenceError> {
|
||||||
|
let name = &circuit.circuit_name.name;
|
||||||
|
|
||||||
|
// Get circuit type from circuit symbol table.
|
||||||
|
let circuit_type = self.table.get_circuit_type(name).unwrap().clone();
|
||||||
|
|
||||||
|
// Create a new function for each circuit member function.
|
||||||
|
for circuit_member in &circuit.members {
|
||||||
|
// ignore circuit member variables
|
||||||
|
if let CircuitMember::CircuitFunction(_, function) = circuit_member {
|
||||||
|
// Collect `TypeAssertion` predicates from the function.
|
||||||
|
// Pass down circuit self type and circuit variable types to each function.
|
||||||
|
let frame = Frame::new_circuit_function(
|
||||||
|
function.to_owned(),
|
||||||
|
circuit_type.clone(),
|
||||||
|
Scope::default(),
|
||||||
|
self.table.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.frames.push(frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Collects a vector of `TypeAssertion` predicates from a vector of functions.
|
||||||
|
///
|
||||||
|
fn parse_functions<'a>(&mut self, functions: impl Iterator<Item = &'a Function>) -> Result<(), TypeInferenceError> {
|
||||||
|
for function in functions {
|
||||||
|
self.parse_function(function)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Collects a vector of `TypeAssertion` predicates from a function.
|
||||||
|
///
|
||||||
|
fn parse_function(&mut self, function: &Function) -> Result<(), TypeInferenceError> {
|
||||||
|
let frame = Frame::new_function(function.to_owned(), None, None, self.table.clone())?;
|
||||||
|
|
||||||
|
self.frames.push(frame);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the result of evaluating all `TypeAssertion` predicates.
|
||||||
|
///
|
||||||
|
/// Will attempt to substitute a `Type` for all `TypeVariable`s.
|
||||||
|
/// Returns a `LeoResolvedAst` if all `TypeAssertion` predicates are true.
|
||||||
|
/// Returns ERROR if a `TypeAssertion` predicate is false or a solution does not exist.
|
||||||
|
///
|
||||||
|
pub fn check(self) -> Result<(), TypeInferenceError> {
|
||||||
|
for frame in self.frames {
|
||||||
|
frame.check()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
3
type-inference/tests/arrays/empty_array.leo
Normal file
3
type-inference/tests/arrays/empty_array.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main() {
|
||||||
|
let a = [1u8; 0]; // Empty arrays are illegal in Leo programs since arrays cannot be resized.
|
||||||
|
}
|
5
type-inference/tests/arrays/invalid_array_access.leo
Normal file
5
type-inference/tests/arrays/invalid_array_access.leo
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
function main() {
|
||||||
|
let a = (1u8, 2u8);
|
||||||
|
|
||||||
|
let b = a[0]; // It is illegal to index into a tuple using bracket syntax.
|
||||||
|
}
|
5
type-inference/tests/arrays/invalid_spread.leo
Normal file
5
type-inference/tests/arrays/invalid_spread.leo
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
function main() {
|
||||||
|
let a: u8 = 1;
|
||||||
|
|
||||||
|
let b = [...a];
|
||||||
|
}
|
44
type-inference/tests/arrays/mod.rs
Normal file
44
type-inference/tests/arrays/mod.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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::TestTypeInference;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_array() {
|
||||||
|
let bytes = include_bytes!("empty_array.leo");
|
||||||
|
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_array_access() {
|
||||||
|
let bytes = include_bytes!("invalid_array_access.leo");
|
||||||
|
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_spread() {
|
||||||
|
let bytes = include_bytes!("invalid_spread.leo");
|
||||||
|
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
4
type-inference/tests/circuits/invalid_circuit.leo
Normal file
4
type-inference/tests/circuits/invalid_circuit.leo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function main() {
|
||||||
|
let a = 1u8;
|
||||||
|
let b = a::foo(); // Variable `a` is not a circuit type.
|
||||||
|
}
|
25
type-inference/tests/circuits/mod.rs
Normal file
25
type-inference/tests/circuits/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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::TestTypeInference;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_circuit() {
|
||||||
|
let bytes = include_bytes!("invalid_circuit.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
0
type-inference/tests/empty.leo
Normal file
0
type-inference/tests/empty.leo
Normal file
4
type-inference/tests/functions/invalid_function.leo
Normal file
4
type-inference/tests/functions/invalid_function.leo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function main() {
|
||||||
|
let a = 1u8;
|
||||||
|
let b = a(); // Variable `a` is not a function.
|
||||||
|
}
|
25
type-inference/tests/functions/mod.rs
Normal file
25
type-inference/tests/functions/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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::TestTypeInference;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_function() {
|
||||||
|
let bytes = include_bytes!("invalid_function.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
84
type-inference/tests/mod.rs
Normal file
84
type-inference/tests/mod.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
pub mod arrays;
|
||||||
|
pub mod circuits;
|
||||||
|
pub mod functions;
|
||||||
|
pub mod tuples;
|
||||||
|
pub mod variables;
|
||||||
|
|
||||||
|
use leo_grammar::Grammar;
|
||||||
|
use leo_type_inference::TypeInference;
|
||||||
|
|
||||||
|
use leo_ast::{Ast, Input, Program};
|
||||||
|
use leo_imports::ImportParser;
|
||||||
|
use leo_symbol_table::SymbolTable;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const TEST_PROGRAM_PATH: &str = "";
|
||||||
|
const TEST_PROGRAM_NAME: &str = "test";
|
||||||
|
|
||||||
|
/// A helper struct to test a `TypeInference` check.
|
||||||
|
pub struct TestTypeInference {
|
||||||
|
program: Program,
|
||||||
|
symbol_table: SymbolTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestTypeInference {
|
||||||
|
pub fn new(bytes: &[u8]) -> Self {
|
||||||
|
// Get file string from bytes.
|
||||||
|
let file_string = String::from_utf8_lossy(bytes);
|
||||||
|
|
||||||
|
// Get test file path.
|
||||||
|
let file_path = PathBuf::from(TEST_PROGRAM_PATH);
|
||||||
|
|
||||||
|
// Get parser syntax tree.
|
||||||
|
let ast = Grammar::new(&file_path, &*file_string).unwrap();
|
||||||
|
|
||||||
|
// Get typed syntax tree.
|
||||||
|
let typed = Ast::new(TEST_PROGRAM_NAME, &ast);
|
||||||
|
let program = typed.into_repr();
|
||||||
|
|
||||||
|
// Create empty import parser.
|
||||||
|
let import_parser = ImportParser::default();
|
||||||
|
|
||||||
|
// Create empty input.
|
||||||
|
let input = Input::new();
|
||||||
|
|
||||||
|
// Create symbol table.
|
||||||
|
let symbol_table = SymbolTable::new(&program, &import_parser, &input).unwrap();
|
||||||
|
|
||||||
|
// Store fields for new type inference check.
|
||||||
|
Self { program, symbol_table }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(self) {
|
||||||
|
TypeInference::new(&self.program, self.symbol_table).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_error(self) {
|
||||||
|
assert!(TypeInference::new(&self.program, self.symbol_table).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
let bytes = include_bytes!("empty.leo");
|
||||||
|
|
||||||
|
let type_inference = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
type_inference.check()
|
||||||
|
}
|
5
type-inference/tests/tuples/invalid_tuple_access.leo
Normal file
5
type-inference/tests/tuples/invalid_tuple_access.leo
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
function main() {
|
||||||
|
let a = [1u8; 3];
|
||||||
|
|
||||||
|
let b = a.0; // It is illegal to index into an array using dot syntax.
|
||||||
|
}
|
25
type-inference/tests/tuples/mod.rs
Normal file
25
type-inference/tests/tuples/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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::TestTypeInference;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_tuple_access() {
|
||||||
|
let bytes = include_bytes!("invalid_tuple_access.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
4
type-inference/tests/variables/duplicate_variable.leo
Normal file
4
type-inference/tests/variables/duplicate_variable.leo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function main() {
|
||||||
|
let a = 1u8;
|
||||||
|
let a = 2u8; // Redefining variables with the same name is unsafe in Leo.
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
function main() {
|
||||||
|
let (a, a) = (2u8, 2u8); // Defining multiple variables with the same name is unsafe in Leo.
|
||||||
|
}
|
49
type-inference/tests/variables/mod.rs
Normal file
49
type-inference/tests/variables/mod.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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::TestTypeInference;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_variable() {
|
||||||
|
let bytes = include_bytes!("duplicate_variable.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_variable_multi() {
|
||||||
|
let bytes = include_bytes!("duplicate_variable_multi.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_enough_values() {
|
||||||
|
let bytes = include_bytes!("not_enough_values.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_too_many_values() {
|
||||||
|
let bytes = include_bytes!("too_many_values.leo");
|
||||||
|
let check = TestTypeInference::new(bytes);
|
||||||
|
|
||||||
|
check.expect_error();
|
||||||
|
}
|
3
type-inference/tests/variables/not_enough_values.leo
Normal file
3
type-inference/tests/variables/not_enough_values.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main() {
|
||||||
|
let (a, b): (u8, u8) = 1; // A tuple of values must be used when defining two variables.
|
||||||
|
}
|
3
type-inference/tests/variables/too_many_values.leo
Normal file
3
type-inference/tests/variables/too_many_values.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main() {
|
||||||
|
let (a, b): (u8, u8) = (1, 2, 3); // Cannot assign 2 variables to 3 values.
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user