mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-01 18:56:38 +03:00
impl symbol table for pass 1 + pass 2 type resolution
This commit is contained in:
parent
dd70318531
commit
d5a9cefe7c
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1334,6 +1334,7 @@ dependencies = [
|
||||
"leo-input",
|
||||
"leo-package",
|
||||
"leo-state",
|
||||
"leo-symbol-table",
|
||||
"notify",
|
||||
"num-bigint",
|
||||
"rand",
|
||||
@ -1393,6 +1394,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leo-symbol-table"
|
||||
version = "1.0.3"
|
||||
dependencies = [
|
||||
"leo-ast",
|
||||
"leo-imports",
|
||||
"leo-typed",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leo-typed"
|
||||
version = "1.0.3"
|
||||
|
@ -35,7 +35,8 @@ members = [
|
||||
"linter",
|
||||
"package",
|
||||
"typed",
|
||||
"state"
|
||||
"state",
|
||||
"symbol-table",
|
||||
]
|
||||
|
||||
[dependencies.leo-compiler]
|
||||
@ -66,6 +67,10 @@ version = "1.0.3"
|
||||
path = "./state"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.leo-symbol-table]
|
||||
path = "./symbol-table"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.snarkos-algorithms]
|
||||
version = "1.1.3"
|
||||
default-features = false
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
||||
GroupType,
|
||||
};
|
||||
|
||||
use leo_typed::{Expression, Function, InputVariable, Span, Type};
|
||||
use leo_typed::{Expression, Function, FunctionInput, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -57,7 +57,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Store input values as new variables in resolved program
|
||||
for (input_model, input_expression) in function.input.clone().iter().zip(input.into_iter()) {
|
||||
let (name, value) = match input_model {
|
||||
InputVariable::InputKeyword(identifier) => {
|
||||
FunctionInput::InputKeyword(identifier) => {
|
||||
let input_value = self.enforce_function_input(
|
||||
cs,
|
||||
scope.clone(),
|
||||
@ -69,7 +69,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
(identifier.name.clone(), input_value)
|
||||
}
|
||||
InputVariable::FunctionInput(input_model) => {
|
||||
FunctionInput::Variable(input_model) => {
|
||||
// First evaluate input expression
|
||||
let mut input_value = self.enforce_function_input(
|
||||
cs,
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
||||
OutputBytes,
|
||||
};
|
||||
|
||||
use leo_typed::{Expression, Function, Input, InputVariable};
|
||||
use leo_typed::{Expression, Function, FunctionInput, Input};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -45,12 +45,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let mut input_variables = vec![];
|
||||
for input_model in function.input.clone().into_iter() {
|
||||
let (identifier, value) = match input_model {
|
||||
InputVariable::InputKeyword(identifier) => {
|
||||
FunctionInput::InputKeyword(identifier) => {
|
||||
let value = self.allocate_input_keyword(cs, identifier.clone(), &input)?;
|
||||
|
||||
(identifier, value)
|
||||
}
|
||||
InputVariable::FunctionInput(input_model) => {
|
||||
FunctionInput::Variable(input_model) => {
|
||||
let name = input_model.identifier.name.clone();
|
||||
let input_option = input
|
||||
.get(&name)
|
||||
|
@ -22,8 +22,8 @@ use leo_typed::{
|
||||
Expression,
|
||||
Function,
|
||||
FunctionInput,
|
||||
FunctionInputVariable,
|
||||
Identifier,
|
||||
InputVariable,
|
||||
IntegerType,
|
||||
Span,
|
||||
Statement,
|
||||
@ -67,7 +67,7 @@ impl CoreCircuit for Blake2sCircuit {
|
||||
span: span.clone(),
|
||||
},
|
||||
input: vec![
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
FunctionInput::Variable(FunctionInputVariable {
|
||||
identifier: Identifier {
|
||||
name: "seed".to_owned(),
|
||||
span: span.clone(),
|
||||
@ -76,7 +76,7 @@ impl CoreCircuit for Blake2sCircuit {
|
||||
type_: Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize]),
|
||||
span: span.clone(),
|
||||
}),
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
FunctionInput::Variable(FunctionInputVariable {
|
||||
identifier: Identifier {
|
||||
name: "message".to_owned(),
|
||||
span: span.clone(),
|
||||
|
36
symbol-table/Cargo.toml
Normal file
36
symbol-table/Cargo.toml
Normal file
@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "leo-symbol-table"
|
||||
version = "1.0.3"
|
||||
authors = [ "The Aleo Team <hello@aleo.org>" ]
|
||||
description = "Stores user-defined variables during type resolution"
|
||||
homepage = "https://aleo.org"
|
||||
respository = "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.3"
|
||||
|
||||
[dependencies.leo-imports]
|
||||
path = "../imports"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.leo-typed]
|
||||
path = "../typed"
|
||||
version = "1.0.3"
|
||||
|
||||
[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, 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_::*;
|
67
symbol-table/src/errors/symbol_table.rs
Normal file
67
symbol-table/src/errors/symbol_table.rs
Normal file
@ -0,0 +1,67 @@
|
||||
// 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;
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Errors encountered when tracking variable, function, and circuit names in a program
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SymbolTableError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
TypeError(#[from] TypeError),
|
||||
}
|
||||
|
||||
impl SymbolTableError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace
|
||||
///
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
match self {
|
||||
SymbolTableError::Error(error) => error.set_path(path),
|
||||
SymbolTableError::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 {
|
||||
SymbolTableError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Two circuits have been defined with the same name
|
||||
///
|
||||
pub fn duplicate_circuit(identifier: Identifier, span: Span) -> Self {
|
||||
let message = format!("Duplicate circuit definition found for `{}`", identifier);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Two functions have been defined with the same name
|
||||
///
|
||||
pub fn duplicate_function(identifier: Identifier, span: Span) -> Self {
|
||||
let message = format!("Duplicate function definition found for `{}`", identifier);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
141
symbol-table/src/errors/type_.rs
Normal file
141
symbol-table/src/errors/type_.rs
Normal file
@ -0,0 +1,141 @@
|
||||
// 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::Type;
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// 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: PathBuf) {
|
||||
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))
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected an array type from the given expression.
|
||||
///
|
||||
pub fn invalid_array(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected array type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a circuit type from the given expression.
|
||||
///
|
||||
pub fn invalid_circuit(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected circuit type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a function type from the given expression.
|
||||
///
|
||||
pub fn invalid_function(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected function type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected an integer type from the given expression.
|
||||
///
|
||||
pub fn invalid_integer(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected integer type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a tuple type from the given expression.
|
||||
///
|
||||
pub fn invalid_tuple(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected tuple type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// The value of the expression does not match the given explicit type.
|
||||
///
|
||||
pub fn mismatched_types(expected: &Type, actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected type `{}`, found type `{}`.", expected, actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// The `Self` keyword was used outside of a circuit.
|
||||
///
|
||||
pub fn self_not_available(span: Span) -> Self {
|
||||
let message = format!("Type `Self` is only available in circuit definitions and circuit functions.");
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
52
symbol-table/src/lib.rs
Normal file
52
symbol-table/src/lib.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// 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/>.
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod attributes;
|
||||
pub use self::attributes::*;
|
||||
|
||||
pub mod errors;
|
||||
pub use self::errors::*;
|
||||
|
||||
pub mod symbol_table;
|
||||
pub use self::symbol_table::*;
|
||||
|
||||
pub mod types;
|
||||
pub use self::types::*;
|
||||
|
||||
/// A resolved node in an abstract syntax tree (AST).
|
||||
///
|
||||
/// Resolved nodes can be any function, statement, expression, type, etc. in an AST.
|
||||
/// Resolved nodes should not contain any illegal types.
|
||||
/// Resolved nodes should not contain any implicit types.
|
||||
pub trait ResolvedNode {
|
||||
/// The expected error type if the type resolution fails.
|
||||
type Error;
|
||||
|
||||
/// The unresolved AST node that is being resolved.
|
||||
type UnresolvedNode;
|
||||
|
||||
///
|
||||
/// Returns a resolved AST representation given an unresolved AST representation.
|
||||
///
|
||||
/// User-defined types are looked up using the given symbol table.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
}
|
291
symbol-table/src/symbol_table.rs
Normal file
291
symbol-table/src/symbol_table.rs
Normal file
@ -0,0 +1,291 @@
|
||||
// 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, FunctionType, ResolvedNode, SymbolTableError, VariableType};
|
||||
use leo_typed::{Circuit, Function, Identifier, Program as UnresolvedProgram};
|
||||
|
||||
use leo_imports::ImportParser;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A abstract data type that tracks the current bindings of identifier
|
||||
/// names to types in 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.
|
||||
/// Children cannot access names in another sibling's symbol table.
|
||||
#[derive(Clone)]
|
||||
pub struct SymbolTable {
|
||||
/// Maps variable name -> variable type.
|
||||
variables: HashMap<String, VariableType>,
|
||||
|
||||
/// 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 {
|
||||
///
|
||||
/// Creates a new symbol table with a given parent symbol table.
|
||||
///
|
||||
pub fn new(parent: Option<Box<SymbolTable>>) -> Self {
|
||||
SymbolTable {
|
||||
variables: HashMap::new(),
|
||||
circuits: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
parent,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert a variable 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_variable(&mut self, name: String, variable_type: VariableType) -> Option<VariableType> {
|
||||
self.variables.insert(name, variable_type)
|
||||
}
|
||||
|
||||
///
|
||||
/// 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(&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(&mut self, identifier: Identifier, function_type: FunctionType) -> Option<FunctionType> {
|
||||
self.functions.insert(identifier.name, function_type)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the variable type corresponding to the name.
|
||||
///
|
||||
/// If the symbol table did not have this name present, then `None` is returned.
|
||||
///
|
||||
pub fn get_variable(&self, name: &String) -> Option<&VariableType> {
|
||||
// Lookup variable name in symbol table.
|
||||
match self.variables.get(name) {
|
||||
Some(variable) => Some(variable),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 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(&self, name: &String) -> 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(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(&self, key: &String) -> Option<&FunctionType> {
|
||||
// Lookup name in symbol table.
|
||||
match self.functions.get(key) {
|
||||
Some(circuit) => Some(circuit),
|
||||
None => {
|
||||
// Lookup name in parent symbol table
|
||||
match &self.parent {
|
||||
Some(parent) => parent.get_function(key),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts all imported identifiers for a given list of imported programs.
|
||||
///
|
||||
/// No type resolution performed at this step.
|
||||
///
|
||||
pub fn insert_imports(&mut self, _imports: ImportParser) {}
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit names given a hashmap of unresolved circuits.
|
||||
///
|
||||
/// If a circuit 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_duplicate_circuits(
|
||||
&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.
|
||||
let duplicate = self.insert_variable(identifier.to_string(), VariableType::from(circuit.clone()));
|
||||
|
||||
// Check that the circuit name is unique.
|
||||
if duplicate.is_some() {
|
||||
return Err(SymbolTableError::duplicate_circuit(
|
||||
identifier.clone(),
|
||||
circuit.circuit_name.span.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate function names given a hashmap of unresolved functions.
|
||||
///
|
||||
/// If a 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_duplicate_functions(
|
||||
&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.
|
||||
let duplicate = self.insert_variable(identifier.to_string(), VariableType::from(function.clone()));
|
||||
|
||||
// Check that the function name is unique.
|
||||
if duplicate.is_some() {
|
||||
return Err(SymbolTableError::duplicate_function(
|
||||
identifier.clone(),
|
||||
function.identifier.span.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for unknown types in a circuit given a hashmap of unresolved circuits.
|
||||
///
|
||||
/// If a circuit 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_unknown_types_circuits(
|
||||
&mut self,
|
||||
circuits: &HashMap<Identifier, Circuit>,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Iterate over circuit names and definitions.
|
||||
for (_, circuit) in circuits.iter() {
|
||||
// Get the identifier of the unresolved circuit.
|
||||
let identifier = circuit.circuit_name.clone();
|
||||
|
||||
// Resolve unknown types in the unresolved circuit definition.
|
||||
let circuit_type = CircuitType::resolve(self, circuit.clone())?;
|
||||
|
||||
// Attempt to insert the circuit definition into the symbol table.
|
||||
self.insert_circuit(identifier, circuit_type);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for unknown types in a function given a hashmap of unresolved functions.
|
||||
///
|
||||
/// If a 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_unknown_types_functions(
|
||||
&mut self,
|
||||
functions: &HashMap<Identifier, Function>,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Iterate over function names and definitions.
|
||||
for (_, function) in functions.iter() {
|
||||
// Get the identifier of the unresolved function.
|
||||
let identifier = function.identifier.clone();
|
||||
|
||||
// Resolve unknown types in the unresolved function definition.
|
||||
let function_type = FunctionType::resolve(self, function.clone())?;
|
||||
|
||||
// Attempt to insert the function definition into the symbol table.
|
||||
self.insert_function(identifier, function_type);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit and function names given an unresolved 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 pass_one(&mut self, program: &UnresolvedProgram) -> Result<(), SymbolTableError> {
|
||||
// Check unresolved program circuit names.
|
||||
self.check_duplicate_circuits(&program.circuits)?;
|
||||
|
||||
// Check unresolved program function names.
|
||||
self.check_duplicate_functions(&program.functions)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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 pass_two(&mut self, program: &UnresolvedProgram) -> Result<(), SymbolTableError> {
|
||||
// Check unresolved program circuit definitions.
|
||||
self.check_unknown_types_circuits(&program.circuits)?;
|
||||
|
||||
// Check unresolved program function definitions.
|
||||
self.check_unknown_types_functions(&program.functions)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
144
symbol-table/src/types/circuits/circuit.rs
Normal file
144
symbol-table/src/types/circuits/circuit.rs
Normal file
@ -0,0 +1,144 @@
|
||||
// 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,
|
||||
ResolvedNode,
|
||||
SymbolTable,
|
||||
Type,
|
||||
TypeError,
|
||||
};
|
||||
use leo_typed::{Circuit, CircuitMember, Identifier};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 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, PartialEq, Eq, Hash, 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 ResolvedNode for CircuitType {
|
||||
type Error = TypeError;
|
||||
type UnresolvedNode = Circuit;
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error> {
|
||||
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::from_circuit(
|
||||
table,
|
||||
type_,
|
||||
circuit_identifier.clone(),
|
||||
circuit_identifier.span.clone(),
|
||||
)?;
|
||||
|
||||
// Check if the circuit member variable is mutable.
|
||||
let attributes = if is_mutable { vec![Attribute::Mutable] } else { vec![] };
|
||||
|
||||
// Create a new circuit variable type.
|
||||
let variable = CircuitVariableType {
|
||||
identifier: variable_identifier,
|
||||
type_,
|
||||
attributes,
|
||||
};
|
||||
|
||||
// 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 attributes = if is_static { vec![Attribute::Static] } else { vec![] };
|
||||
|
||||
// Create a new circuit function type.
|
||||
let function = CircuitFunctionType {
|
||||
function: function_type,
|
||||
attributes,
|
||||
};
|
||||
|
||||
// Store the circuit function type.
|
||||
functions.push(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a new circuit type.
|
||||
Ok(CircuitType {
|
||||
identifier: circuit_identifier.clone(),
|
||||
variables,
|
||||
functions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CircuitType {
|
||||
///
|
||||
/// 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_),
|
||||
None => {
|
||||
// Check if the circuit member is a circuit function.
|
||||
let matched_function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|function| function.function.identifier.eq(identifier));
|
||||
|
||||
match matched_function {
|
||||
Some(function) => Ok(&function.function.output.type_),
|
||||
None => Err(TypeError::undefined_circuit_member(identifier.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
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 attributes: Vec<Attribute>,
|
||||
}
|
30
symbol-table/src/types/circuits/circuit_variable.rs
Normal file
30
symbol-table/src/types/circuits/circuit_variable.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/>.
|
||||
|
||||
use crate::{Attribute, Type};
|
||||
use leo_typed::Identifier;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct CircuitVariableType {
|
||||
/// The name of the circuit variable
|
||||
pub identifier: Identifier,
|
||||
/// The type of the circuit variable
|
||||
pub type_: Type,
|
||||
/// The attributes of the circuit variable
|
||||
pub attributes: Vec<Attribute>,
|
||||
}
|
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::*;
|
127
symbol-table/src/types/functions/function.rs
Normal file
127
symbol-table/src/types/functions/function.rs
Normal file
@ -0,0 +1,127 @@
|
||||
// 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},
|
||||
ResolvedNode,
|
||||
SymbolTable,
|
||||
TypeError,
|
||||
};
|
||||
use leo_typed::{Function, Identifier};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 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, PartialEq, Eq, Hash, 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 ResolvedNode for FunctionType {
|
||||
type Error = TypeError;
|
||||
type UnresolvedNode = Function;
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error> {
|
||||
let mut inputs_resolved = vec![];
|
||||
|
||||
// Type check function inputs
|
||||
for input in unresolved.input {
|
||||
let input = FunctionInputType::resolve(table, input)?;
|
||||
inputs_resolved.push(input);
|
||||
}
|
||||
|
||||
// Type check function output
|
||||
let output = FunctionOutputType::resolve(table, (unresolved.returns, unresolved.span))?;
|
||||
|
||||
Ok(FunctionType {
|
||||
identifier: unresolved.identifier,
|
||||
inputs: inputs_resolved,
|
||||
output,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionType {
|
||||
///
|
||||
/// 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::resolve(table, unresolved_function)?;
|
||||
|
||||
// Insert (function_identifier -> function_type) as a (key -> value) pair in the symbol table.
|
||||
table.insert_function(function_identifier, function);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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: &mut SymbolTable,
|
||||
circuit_name: Identifier,
|
||||
unresolved_function: Function,
|
||||
) -> Result<Self, TypeError> {
|
||||
let function_identifier = unresolved_function.identifier;
|
||||
let mut inputs = vec![];
|
||||
|
||||
// Type check function inputs.
|
||||
for unresolved_input in unresolved_function.input {
|
||||
let input = FunctionInputType::from_circuit(table, unresolved_input, circuit_name.clone())?;
|
||||
inputs.push(input);
|
||||
}
|
||||
|
||||
// Type check function output.
|
||||
let output = FunctionOutputType::from_circuit(
|
||||
table,
|
||||
circuit_name.clone(),
|
||||
unresolved_function.returns,
|
||||
unresolved_function.span,
|
||||
)?;
|
||||
|
||||
Ok(FunctionType {
|
||||
identifier: function_identifier.clone(),
|
||||
inputs,
|
||||
output,
|
||||
})
|
||||
}
|
||||
}
|
109
symbol-table/src/types/functions/function_input.rs
Normal file
109
symbol-table/src/types/functions/function_input.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// 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, ResolvedNode, SymbolTable, Type, TypeError, VariableType};
|
||||
use leo_typed::{FunctionInput, Identifier};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum FunctionInputType {
|
||||
InputKeyword(Identifier),
|
||||
Variable(FunctionInputVariableType),
|
||||
}
|
||||
|
||||
impl ResolvedNode for FunctionInputType {
|
||||
type Error = TypeError;
|
||||
type UnresolvedNode = FunctionInput;
|
||||
|
||||
///
|
||||
/// Return a new `FunctionInputType` from a given `FunctionInput`.
|
||||
///
|
||||
/// Performs a lookup in the given symbol table if the function input contains
|
||||
/// user-defined types.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error> {
|
||||
Ok(match unresolved {
|
||||
FunctionInput::InputKeyword(identifier) => FunctionInputType::InputKeyword(identifier),
|
||||
FunctionInput::Variable(variable) => {
|
||||
let variable_resolved = FunctionInputVariableType::resolve(table, variable)?;
|
||||
|
||||
FunctionInputType::Variable(variable_resolved)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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(_) => unimplemented!("ERROR: input type not implemented"),
|
||||
FunctionInputType::Variable(variable) => &variable.type_,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 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 from_circuit(
|
||||
table: &mut 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::from_circuit(table, unresolved_function_input, circuit_name)?;
|
||||
|
||||
FunctionInputType::Variable(function_input)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert the current function input type into the given symbol table.
|
||||
///
|
||||
/// If the symbol table did not have this name present, `None` is returned.
|
||||
///
|
||||
pub fn insert(&self, table: &mut SymbolTable) -> Option<VariableType> {
|
||||
match self {
|
||||
FunctionInputType::Variable(variable) => variable.insert(table),
|
||||
FunctionInputType::InputKeyword(_identifier) => {
|
||||
unimplemented!("uncomment when support for input types is added")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
symbol-table/src/types/functions/function_input_variable.rs
Normal file
108
symbol-table/src/types/functions/function_input_variable.rs
Normal file
@ -0,0 +1,108 @@
|
||||
// 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, ResolvedNode, SymbolTable, Type, TypeError, VariableType};
|
||||
use leo_typed::{FunctionInputVariable, Identifier, Span};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, 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 attributes: Vec<Attribute>,
|
||||
|
||||
/// The span of the function input.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl ResolvedNode for FunctionInputVariableType {
|
||||
type Error = TypeError;
|
||||
type UnresolvedNode = FunctionInputVariable;
|
||||
|
||||
///
|
||||
/// Return a new `FunctionInputVariableType` from a given `FunctionInputVariable`.
|
||||
///
|
||||
/// Performs a lookup in the given symbol table if the type is user-defined.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error> {
|
||||
let type_ = Type::resolve(table, (unresolved.type_, unresolved.span.clone()))?;
|
||||
let attributes = if unresolved.mutable {
|
||||
vec![Attribute::Mutable]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
Ok(FunctionInputVariableType {
|
||||
identifier: unresolved.identifier,
|
||||
type_,
|
||||
attributes,
|
||||
span: unresolved.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.
|
||||
///
|
||||
/// If the type of the function return type is the `Self` keyword, then the given circuit
|
||||
/// identifier is used as the type.
|
||||
///
|
||||
pub fn from_circuit(
|
||||
table: &mut SymbolTable,
|
||||
unresolved_function_input: FunctionInputVariable,
|
||||
circuit_name: Identifier,
|
||||
) -> Result<Self, TypeError> {
|
||||
let type_ = Type::from_circuit(
|
||||
table,
|
||||
unresolved_function_input.type_,
|
||||
circuit_name,
|
||||
unresolved_function_input.span.clone(),
|
||||
)?;
|
||||
let attributes = if unresolved_function_input.mutable {
|
||||
vec![Attribute::Mutable]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
Ok(FunctionInputVariableType {
|
||||
identifier: unresolved_function_input.identifier,
|
||||
type_,
|
||||
attributes,
|
||||
span: unresolved_function_input.span,
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert the current function input variable type into the given symbol table.
|
||||
///
|
||||
/// If the symbol table did not have this name present, `None` is returned.
|
||||
///
|
||||
pub fn insert(&self, table: &mut SymbolTable) -> Option<VariableType> {
|
||||
let key = self.identifier.name.clone();
|
||||
let value = VariableType::from(self.clone());
|
||||
|
||||
table.insert_variable(key, value)
|
||||
}
|
||||
}
|
74
symbol-table/src/types/functions/function_output.rs
Normal file
74
symbol-table/src/types/functions/function_output.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::{ResolvedNode, SymbolTable, Type, TypeError};
|
||||
|
||||
use leo_typed::{Identifier, Span, Type as UnresolvedType};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct FunctionOutputType {
|
||||
/// Type of function output.
|
||||
pub type_: Type,
|
||||
}
|
||||
|
||||
impl ResolvedNode for FunctionOutputType {
|
||||
type Error = TypeError;
|
||||
/// (optional function output, span)
|
||||
type UnresolvedNode = (Option<UnresolvedType>, Span);
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, TypeError> {
|
||||
let function_output = unresolved.0;
|
||||
let span = unresolved.1;
|
||||
|
||||
let type_ = match function_output {
|
||||
None => Type::Tuple(vec![]), // functions with no return value return an empty tuple
|
||||
Some(type_) => Type::resolve(table, (type_, span))?,
|
||||
};
|
||||
|
||||
Ok(FunctionOutputType { 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.
|
||||
///
|
||||
/// If the type of the function return type is the `Self` keyword, then the given circuit
|
||||
/// identifier is used as the type.
|
||||
///
|
||||
pub fn from_circuit(
|
||||
table: &mut SymbolTable,
|
||||
circuit_name: Identifier,
|
||||
unresolved: Option<UnresolvedType>,
|
||||
span: Span,
|
||||
) -> Result<Self, TypeError> {
|
||||
let output_type = match unresolved {
|
||||
None => Type::Tuple(vec![]),
|
||||
Some(type_) => Type::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::*;
|
27
symbol-table/src/types/mod.rs
Normal file
27
symbol-table/src/types/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 circuits;
|
||||
pub use self::circuits::*;
|
||||
|
||||
pub mod functions;
|
||||
pub use self::functions::*;
|
||||
|
||||
pub mod type_;
|
||||
pub use self::type_::*;
|
||||
|
||||
pub mod variables;
|
||||
pub use self::variables::*;
|
221
symbol-table/src/types/type_.rs
Normal file
221
symbol-table/src/types/type_.rs
Normal file
@ -0,0 +1,221 @@
|
||||
// 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::{ResolvedNode, SymbolTable, TypeError};
|
||||
use leo_typed::{Identifier, IntegerType, Span, Type as UnresolvedType};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A resolved type in a Leo program.
|
||||
///
|
||||
/// This type cannot be an implicit or `Self` type.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Type {
|
||||
// Data types
|
||||
Address,
|
||||
Boolean,
|
||||
Field,
|
||||
Group,
|
||||
IntegerType(IntegerType),
|
||||
|
||||
// Data type wrappers
|
||||
Array(Box<Type>, Vec<usize>),
|
||||
Tuple(Vec<Type>),
|
||||
|
||||
// User defined types
|
||||
Circuit(Identifier),
|
||||
Function(Identifier),
|
||||
}
|
||||
|
||||
impl ResolvedNode for Type {
|
||||
type Error = TypeError;
|
||||
type UnresolvedNode = (UnresolvedType, Span);
|
||||
|
||||
///
|
||||
/// Resolves the given type.
|
||||
///
|
||||
/// Cannot be an implicit or `Self` type.
|
||||
///
|
||||
fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result<Self, Self::Error> {
|
||||
let type_ = unresolved.0;
|
||||
let span = unresolved.1;
|
||||
|
||||
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_, dimensions) => {
|
||||
let array_type = Type::resolve(table, (*type_, span))?;
|
||||
|
||||
Type::Array(Box::new(array_type), dimensions)
|
||||
}
|
||||
UnresolvedType::Tuple(types) => {
|
||||
let tuple_types = types
|
||||
.into_iter()
|
||||
.map(|type_| Type::resolve(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(&identifier.name)
|
||||
.ok_or(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));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
///
|
||||
/// Resolve a type inside of a circuit definition.
|
||||
///
|
||||
/// If this type is SelfType, return the circuit's type.
|
||||
///
|
||||
pub fn from_circuit(
|
||||
table: &mut SymbolTable,
|
||||
type_: UnresolvedType,
|
||||
circuit_name: Identifier,
|
||||
span: Span,
|
||||
) -> Result<Self, TypeError> {
|
||||
Ok(match type_ {
|
||||
UnresolvedType::Array(type_, dimensions) => {
|
||||
let array_type = Type::from_circuit(table, *type_, circuit_name, span)?;
|
||||
Type::Array(Box::new(array_type), dimensions)
|
||||
}
|
||||
UnresolvedType::Tuple(types) => {
|
||||
let tuple_types = types
|
||||
.into_iter()
|
||||
.map(|type_| Type::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::resolve(table, (unresolved, span))?,
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `Ok` if the given expected type is `Some` and expected type == actual type.
|
||||
///
|
||||
pub fn check_type(expected_option: &Option<Self>, actual: &Type, span: Span) -> Result<(), TypeError> {
|
||||
if let Some(expected) = expected_option {
|
||||
if expected.ne(actual) {
|
||||
return Err(TypeError::mismatched_types(expected, actual, span));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `Ok` if self is an expected integer type `Type::IntegerType`.
|
||||
///
|
||||
pub fn check_type_integer(&self, span: Span) -> Result<(), TypeError> {
|
||||
match self {
|
||||
Type::IntegerType(_) => Ok(()),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_integer(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns array element type and dimensions if self is an expected array type `Type::Array`.
|
||||
///
|
||||
pub fn get_type_array(&self, span: Span) -> Result<(&Type, &Vec<usize>), TypeError> {
|
||||
match self {
|
||||
Type::Array(element_type, dimensions) => Ok((element_type, dimensions)),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_array(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns tuple element types if self is an expected tuple type `Type::Tuple`.
|
||||
///
|
||||
pub fn get_type_tuple(&self, span: Span) -> Result<&Vec<Type>, TypeError> {
|
||||
match self {
|
||||
Type::Tuple(types) => Ok(types),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_tuple(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns circuit identifier if self is an expected circuit type `Type::Circuit`.
|
||||
///
|
||||
pub fn get_type_circuit(&self, span: Span) -> Result<&Identifier, TypeError> {
|
||||
match self {
|
||||
Type::Circuit(identifier) => Ok(identifier),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_circuit(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns function identifier if self is an expected function type `Type::Function`.
|
||||
///
|
||||
pub fn get_type_function(&self, span: Span) -> Result<&Identifier, TypeError> {
|
||||
match self {
|
||||
Type::Function(identifier) => Ok(identifier),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_function(type_, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_, dimensions) => {
|
||||
let dimensions_string = dimensions
|
||||
.iter()
|
||||
.map(|dimension| format!("{}", dimension))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
write!(f, "[{}; ({})]", *type_, dimensions_string)
|
||||
}
|
||||
Type::Tuple(tuple) => {
|
||||
let tuple_string = tuple.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(", ");
|
||||
|
||||
write!(f, "({})", tuple_string)
|
||||
}
|
||||
|
||||
Type::Circuit(identifier) => write!(f, "circuit {}", identifier),
|
||||
Type::Function(identifier) => write!(f, "function {}", identifier),
|
||||
}
|
||||
}
|
||||
}
|
18
symbol-table/src/types/variables/mod.rs
Normal file
18
symbol-table/src/types/variables/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 variable;
|
||||
pub use self::variable::*;
|
79
symbol-table/src/types/variables/variable.rs
Normal file
79
symbol-table/src/types/variables/variable.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// 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, Type};
|
||||
use leo_typed::{Circuit, Function, Identifier};
|
||||
|
||||
use crate::FunctionInputVariableType;
|
||||
use std::fmt;
|
||||
|
||||
/// Stores variable definition details.
|
||||
///
|
||||
/// This type should be added to the variable symbol table for a resolved syntax tree.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct VariableType {
|
||||
pub identifier: Identifier,
|
||||
pub type_: Type,
|
||||
pub attributes: Vec<Attribute>,
|
||||
}
|
||||
|
||||
impl VariableType {
|
||||
///
|
||||
/// Returns `true` if this variable's value can be modified.
|
||||
///
|
||||
pub fn is_mutable(&self) -> bool {
|
||||
self.attributes.contains(&Attribute::Mutable)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Circuit> for VariableType {
|
||||
fn from(value: Circuit) -> Self {
|
||||
let identifier = value.circuit_name;
|
||||
|
||||
VariableType {
|
||||
identifier: identifier.clone(),
|
||||
type_: Type::Circuit(identifier),
|
||||
attributes: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Function> for VariableType {
|
||||
fn from(value: Function) -> Self {
|
||||
let identifier = value.identifier;
|
||||
|
||||
VariableType {
|
||||
identifier: identifier.clone(),
|
||||
type_: Type::Function(identifier.clone()),
|
||||
attributes: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FunctionInputVariableType> for VariableType {
|
||||
fn from(value: FunctionInputVariableType) -> Self {
|
||||
VariableType {
|
||||
identifier: value.identifier,
|
||||
type_: value.type_,
|
||||
attributes: value.attributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VariableType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.identifier)
|
||||
}
|
||||
}
|
115
symbol-table/tests/mod.rs
Normal file
115
symbol-table/tests/mod.rs
Normal file
@ -0,0 +1,115 @@
|
||||
// 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::LeoAst;
|
||||
use leo_symbol_table::{SymbolTable, SymbolTableError};
|
||||
use leo_typed::LeoTypedAst;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
const TEST_PROGRAM_PATH: &str = "";
|
||||
|
||||
/// A helper struct to test a `SymbolTable`.
|
||||
pub struct TestSymbolTable {
|
||||
typed: LeoTypedAst,
|
||||
}
|
||||
|
||||
impl TestSymbolTable {
|
||||
///
|
||||
/// Returns a typed 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 ast = LeoAst::new(&file_path, &*file_string).unwrap();
|
||||
|
||||
// Get typed syntax tree
|
||||
let typed = LeoTypedAst::new(TEST_PROGRAM_PATH, &ast);
|
||||
|
||||
Self { typed }
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse the typed syntax tree into a symbol table.
|
||||
///
|
||||
/// Expect no errors during parsing.
|
||||
///
|
||||
pub fn expect_success(self) {
|
||||
// Get program.
|
||||
let program = self.typed.into_repr();
|
||||
|
||||
// Create new symbol table.
|
||||
let symbol_table = &mut SymbolTable::new(None);
|
||||
|
||||
// Run the first pass to check for duplicate names.
|
||||
symbol_table.pass_one(&program).unwrap();
|
||||
|
||||
// Run the second pass to check for invalid definitions.
|
||||
symbol_table.pass_two(&program).unwrap();
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse the typed 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.typed.into_repr();
|
||||
|
||||
// Create new symbol table.
|
||||
let symbol_table = &mut SymbolTable::new(None);
|
||||
|
||||
// Run pass one and expect an error.
|
||||
let error = symbol_table.pass_one(&program).unwrap_err();
|
||||
|
||||
match error {
|
||||
SymbolTableError::Error(_) => {} // Ok
|
||||
error => panic!("Expected a symbol table error found `{}`", error),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Parse the typed 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.typed.into_repr();
|
||||
|
||||
// Create a new symbol table.
|
||||
let symbol_table = &mut SymbolTable::new(None);
|
||||
|
||||
// Run the pass one and expect no errors.
|
||||
symbol_table.pass_one(&program).unwrap();
|
||||
|
||||
// Run the pass two and expect and error.
|
||||
let error = symbol_table.pass_two(&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() {}
|
72
symbol-table/tests/symbol_table/mod.rs
Normal file
72
symbol-table/tests/symbol_table/mod.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::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
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Circuit, Function, Identifier, Import, InputVariable, TestFunction};
|
||||
use crate::{Circuit, Function, FunctionInput, Identifier, Import, TestFunction};
|
||||
use leo_ast::{
|
||||
annotations::{Annotation, AnnotationArguments, AnnotationName},
|
||||
definitions::{AnnotatedDefinition, Definition},
|
||||
@ -28,7 +28,7 @@ pub fn load_annotation(
|
||||
_circuits: &mut HashMap<Identifier, Circuit>,
|
||||
_functions: &mut HashMap<Identifier, Function>,
|
||||
tests: &mut HashMap<Identifier, TestFunction>,
|
||||
_expected: &mut Vec<InputVariable>,
|
||||
_expected: &mut Vec<FunctionInput>,
|
||||
) {
|
||||
let ast_annotation = annotated_definition.annotation;
|
||||
let ast_definition = *annotated_definition.definition;
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Identifier, InputVariable, Span, Statement, Type};
|
||||
use crate::{FunctionInput, Identifier, Span, Statement, Type};
|
||||
use leo_ast::functions::Function as AstFunction;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -23,7 +23,7 @@ use std::fmt;
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Function {
|
||||
pub identifier: Identifier,
|
||||
pub input: Vec<InputVariable>,
|
||||
pub input: Vec<FunctionInput>,
|
||||
pub returns: Option<Type>,
|
||||
pub statements: Vec<Statement>,
|
||||
pub span: Span,
|
||||
@ -35,7 +35,7 @@ impl<'ast> From<AstFunction<'ast>> for Function {
|
||||
let parameters = function
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|parameter| InputVariable::from(parameter))
|
||||
.map(|parameter| FunctionInput::from(parameter))
|
||||
.collect();
|
||||
let returns = function.returns.map(|type_| Type::from(type_));
|
||||
let statements = function
|
||||
|
@ -21,16 +21,16 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct FunctionInput {
|
||||
pub struct FunctionInputVariable {
|
||||
pub identifier: Identifier,
|
||||
pub mutable: bool,
|
||||
pub type_: Type,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<AstFunctionInput<'ast>> for FunctionInput {
|
||||
impl<'ast> From<AstFunctionInput<'ast>> for FunctionInputVariable {
|
||||
fn from(parameter: AstFunctionInput<'ast>) -> Self {
|
||||
FunctionInput {
|
||||
FunctionInputVariable {
|
||||
identifier: Identifier::from(parameter.identifier),
|
||||
mutable: parameter.mutable.is_some(),
|
||||
type_: Type::from(parameter.type_),
|
||||
@ -39,7 +39,7 @@ impl<'ast> From<AstFunctionInput<'ast>> for FunctionInput {
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionInput {
|
||||
impl FunctionInputVariable {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// mut var: bool
|
||||
if self.mutable {
|
||||
@ -50,13 +50,13 @@ impl FunctionInput {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FunctionInput {
|
||||
impl fmt::Display for FunctionInputVariable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FunctionInput {
|
||||
impl fmt::Debug for FunctionInputVariable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
|
@ -14,19 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{FunctionInput, Identifier, Span};
|
||||
use crate::{FunctionInputVariable, Identifier, Span};
|
||||
use leo_ast::functions::input::Input as AstInput;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InputVariable {
|
||||
pub enum FunctionInput {
|
||||
InputKeyword(Identifier),
|
||||
FunctionInput(FunctionInput),
|
||||
Variable(FunctionInputVariable),
|
||||
}
|
||||
|
||||
impl<'ast> From<AstInput<'ast>> for InputVariable {
|
||||
impl<'ast> From<AstInput<'ast>> for FunctionInput {
|
||||
fn from(input: AstInput<'ast>) -> Self {
|
||||
match input {
|
||||
AstInput::InputKeyword(input_keyword) => {
|
||||
@ -35,31 +35,31 @@ impl<'ast> From<AstInput<'ast>> for InputVariable {
|
||||
span: Span::from(input_keyword.span),
|
||||
};
|
||||
|
||||
InputVariable::InputKeyword(id)
|
||||
FunctionInput::InputKeyword(id)
|
||||
}
|
||||
AstInput::FunctionInput(function_input) => {
|
||||
InputVariable::FunctionInput(FunctionInput::from(function_input))
|
||||
FunctionInput::Variable(FunctionInputVariable::from(function_input))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputVariable {
|
||||
impl FunctionInput {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InputVariable::InputKeyword(id) => write!(f, "{}", id),
|
||||
InputVariable::FunctionInput(function_input) => write!(f, "{}", function_input),
|
||||
FunctionInput::InputKeyword(id) => write!(f, "{}", id),
|
||||
FunctionInput::Variable(function_input) => write!(f, "{}", function_input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InputVariable {
|
||||
impl fmt::Display for FunctionInput {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InputVariable {
|
||||
impl fmt::Debug for FunctionInput {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! A typed Leo program consists of import, circuit, and function definitions.
|
||||
//! Each defined type consists of typed statements and expressions.
|
||||
|
||||
use crate::{load_annotation, Circuit, Function, Identifier, Import, InputVariable, TestFunction};
|
||||
use crate::{load_annotation, Circuit, Function, FunctionInput, Identifier, Import, TestFunction};
|
||||
use leo_ast::{definitions::Definition, files::File};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -27,7 +27,7 @@ use std::collections::HashMap;
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Program {
|
||||
pub name: String,
|
||||
pub expected_input: Vec<InputVariable>,
|
||||
pub expected_input: Vec<FunctionInput>,
|
||||
pub imports: Vec<Import>,
|
||||
pub circuits: HashMap<Identifier, Circuit>,
|
||||
pub functions: HashMap<Identifier, Function>,
|
||||
|
Loading…
Reference in New Issue
Block a user