Remove InputAST from compiler

This commit is contained in:
Pranav Gaddamadugu 2023-09-29 10:07:35 -04:00 committed by Pranav Gaddamadugu
parent 8cdab3b774
commit d1a1b258ec
15 changed files with 3 additions and 523 deletions

View File

@ -1,29 +0,0 @@
// Copyright (C) 2019-2023 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 super::*;
use crate::{Expression, Identifier, Mode, Type};
/// A single definition inside a section in a state or an input file.
/// Definitions should be structured as: `<name>: <type_> = <value>;`
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Definition {
pub mode: Mode,
pub type_: Type,
pub name: Identifier,
pub value: Expression,
pub span: Span,
}

View File

@ -1,108 +0,0 @@
// Copyright (C) 2019-2023 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::{normalize_json_value, remove_key_from_json, Expression, Struct, Type};
use super::*;
use leo_errors::{AstError, Result};
/// Input data which includes [`ProgramInput`].
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct InputData {
pub program_input: ProgramInput,
}
impl InputData {
/// Serializes the ast into a JSON string.
pub fn to_json_string(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(&self).map_err(|e| AstError::failed_to_convert_ast_to_json_string(&e))?)
}
}
/// A raw unprocessed input or state file data. Used for future conversion
/// into [`ProgramInput`].
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InputAst {
pub sections: Vec<Section>,
}
impl InputAst {
/// Returns all values of the input AST for execution with `leo run`.
pub fn program_inputs(&self, program_name: &str, structs: IndexMap<Symbol, Struct>) -> Vec<String> {
self.sections
.iter()
.filter(|section| section.name() == program_name)
.flat_map(|section| {
section.definitions.iter().map(|definition| match &definition.type_ {
// Handle case where the input may be record.
Type::Identifier(identifier) => {
match structs.get(&identifier.name) {
// TODO: Better error handling.
None => panic!(
"Input error: A struct or record declaration does not exist for {}.",
identifier.name
),
Some(struct_) => match struct_.is_record {
false => definition.value.to_string(),
true => match &definition.value {
// Print out the record interface with visibility.
Expression::Struct(struct_expression) => struct_expression.to_record_string(),
_ => panic!("Input error: Expected a struct expression."),
},
},
}
}
_ => definition.value.to_string(),
})
})
.collect::<Vec<_>>()
}
/// Serializes the `Input` into a JSON Value.
pub fn to_json_value(&self) -> Result<serde_json::Value> {
Ok(serde_json::to_value(self).map_err(|e| AstError::failed_to_convert_ast_to_json_value(&e))?)
}
/// Serializes the input into a JSON file.
pub fn to_json_file(&self, mut path: std::path::PathBuf, file_name: &str) -> Result<()> {
path.push(file_name);
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);
Ok(serde_json::to_writer_pretty(writer, &self)
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
}
/// Serializes the `Input` into a JSON value and removes keys from object mappings before writing to a file.
pub fn to_json_file_without_keys(
&self,
mut path: std::path::PathBuf,
file_name: &str,
excluded_keys: &[&str],
) -> Result<()> {
path.push(file_name);
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);
let mut value = self.to_json_value().unwrap();
for key in excluded_keys {
value = remove_key_from_json(value, key);
}
value = normalize_json_value(value);
Ok(serde_json::to_writer_pretty(writer, &value)
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
}
}

View File

@ -1,71 +0,0 @@
// Copyright (C) 2019-2023 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::{Expression, GroupLiteral, IntegerType, Literal, Node, Type, UnaryOperation};
use leo_errors::{InputError, LeoError, Result};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InputValue {
Address(String),
Boolean(bool),
Field(String),
Group(GroupLiteral),
Integer(IntegerType, String),
}
impl TryFrom<(Type, Expression)> for InputValue {
type Error = LeoError;
fn try_from(value: (Type, Expression)) -> Result<Self> {
Ok(match value {
(type_, Expression::Literal(lit)) => match (type_, lit) {
(Type::Address, Literal::Address(value, _, _)) => Self::Address(value),
(Type::Boolean, Literal::Boolean(value, _, _)) => Self::Boolean(value),
(Type::Field, Literal::Field(value, _, _)) => Self::Field(value),
(Type::Group, Literal::Group(value)) => Self::Group(*value),
(Type::Integer(expected), Literal::Integer(actual, value, span, _)) => {
if expected == actual {
Self::Integer(expected, value)
} else {
return Err(InputError::unexpected_type(expected.to_string(), actual, span).into());
}
}
(x, y) => {
return Err(InputError::unexpected_type(x, &y, y.span()).into());
}
},
(type_, Expression::Unary(unary)) if unary.op == UnaryOperation::Negate => {
InputValue::try_from((type_, *unary.receiver))?
}
(_type_, expr) => return Err(InputError::illegal_expression(&expr, expr.span()).into()),
})
}
}
impl fmt::Display for InputValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InputValue::Address(ref address) => write!(f, "{address}"),
InputValue::Boolean(ref boolean) => write!(f, "{boolean}"),
InputValue::Group(ref group) => write!(f, "{group}"),
InputValue::Field(ref field) => write!(f, "{field}"),
InputValue::Integer(ref type_, ref number) => write!(f, "{number}{type_:?}"),
}
}
}

View File

@ -1,37 +0,0 @@
// Copyright (C) 2019-2023 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 definition;
pub use definition::*;
pub mod input_ast;
pub use input_ast::*;
pub mod input_value;
pub use input_value::*;
pub mod program_input;
pub use program_input::*;
pub mod section;
pub use section::*;
use indexmap::IndexMap;
use leo_errors::{InputError, LeoError, Result};
use leo_span::{sym, Span, Symbol};
use serde::{Deserialize, Serialize};
type Definitions = IndexMap<Symbol, InputValue>;

View File

@ -1,44 +0,0 @@
// Copyright (C) 2019-2023 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 super::*;
/// Processed Program input.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ProgramInput {
pub main: Definitions,
}
impl TryFrom<InputAst> for ProgramInput {
type Error = LeoError;
fn try_from(input: InputAst) -> Result<Self> {
let mut main = IndexMap::new();
for section in input.sections {
let target = match section.name {
sym::main => &mut main,
_ => return Err(InputError::unexpected_section(&["main"], section.name, section.span).into()),
};
for definition in section.definitions {
target.insert(definition.name.name, InputValue::try_from((definition.type_, definition.value))?);
}
}
Ok(ProgramInput { main })
}
}

View File

@ -1,32 +0,0 @@
// Copyright (C) 2019-2023 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 super::*;
/// A single section in an input or a state file.
/// An example of a section would be: `[main]`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Section {
pub name: Symbol,
pub definitions: Vec<Definition>,
pub span: Span,
}
impl Section {
pub fn name(&self) -> String {
self.name.to_string()
}
}

View File

@ -40,9 +40,6 @@ pub use self::functions::*;
pub mod groups;
pub use self::groups::*;
pub mod input;
pub use self::input::*;
pub mod mapping;
pub use self::mapping::*;

View File

@ -17,7 +17,7 @@
//! The compiler for Leo programs.
//!
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
pub use leo_ast::{Ast, InputAst};
pub use leo_ast::Ast;
use leo_ast::{NodeBuilder, Program, Stub};
use leo_errors::{emitter::Handler, CompilerError, Result};
pub use leo_passes::SymbolTable;
@ -45,8 +45,6 @@ pub struct Compiler<'a> {
pub network: String,
/// The AST for the program.
pub ast: Ast,
/// The input ast for the program if it exists.
pub input_ast: Option<InputAst>,
/// Options configuring compilation.
compiler_options: CompilerOptions,
/// The `NodeCounter` used to generate sequentially increasing `NodeID`s.
@ -80,7 +78,6 @@ impl<'a> Compiler<'a> {
program_name,
network,
ast: Ast::new(Program::default()),
input_ast: None,
compiler_options: compiler_options.unwrap_or_default(),
node_builder,
assigner,
@ -141,37 +138,6 @@ impl<'a> Compiler<'a> {
self.parse_program_from_string(&program_string, FileName::Real(self.main_file_path.clone()))
}
/// Parses and stores the input file, constructs a syntax tree, and generates a program input.
pub fn parse_input(&mut self, input_file_path: PathBuf) -> Result<()> {
if input_file_path.exists() {
// Load the input file into the source map.
let input_sf = with_session_globals(|s| s.source_map.load_file(&input_file_path))
.map_err(|e| CompilerError::file_read_error(&input_file_path, e))?;
// Parse and serialize it.
let input_ast =
leo_parser::parse_input(self.handler, &self.node_builder, &input_sf.src, input_sf.start_pos)?;
if self.compiler_options.output.initial_ast {
// Write the input AST snapshot post parsing.
if self.compiler_options.output.ast_spans_enabled {
input_ast.to_json_file(
self.output_directory.clone(),
&format!("{}.initial_input_ast.json", self.program_name),
)?;
} else {
input_ast.to_json_file_without_keys(
self.output_directory.clone(),
&format!("{}.initial_input_ast.json", self.program_name),
&["span"],
)?;
}
}
self.input_ast = Some(input_ast);
}
Ok(())
}
/// Runs the symbol table pass.
pub fn symbol_table_pass(&self) -> Result<SymbolTable> {
let symbol_table = SymbolTableCreator::do_pass((&self.ast, self.handler))?;

View File

@ -44,8 +44,6 @@ pub struct OutputOptions {
pub ast_spans_enabled: bool,
/// If enabled writes the AST after parsing.
pub initial_ast: bool,
/// If enabled writes the input AST after parsing.
pub initial_input_ast: bool,
/// If enabled writes the AST after loop unrolling.
pub unrolled_ast: bool,
/// If enabled writes the AST after static single assignment.

View File

@ -91,7 +91,6 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
type_checked_symbol_table: true,
unrolled_symbol_table: true,
ast_spans_enabled: false,
initial_input_ast: true,
initial_ast: true,
unrolled_ast: true,
ssa_ast: true,

View File

@ -105,7 +105,6 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
type_checked_symbol_table: true,
unrolled_symbol_table: true,
ast_spans_enabled: false,
initial_input_ast: true,
initial_ast: true,
unrolled_ast: true,
ssa_ast: true,

View File

@ -1,70 +0,0 @@
// Copyright (C) 2019-2023 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/>.
#![forbid(unsafe_code)]
use leo_ast::NodeBuilder;
use leo_errors::{emitter::Handler, Result};
use leo_span::symbol::create_session_if_not_set_then;
use clap::Parser;
use std::{
fs,
path::{Path, PathBuf},
};
#[derive(Debug, Parser)]
#[clap(name = "input parser", about = "Parse an Input file and save its JSON representation")]
struct Opt {
/// Path to the input file.
input_path: PathBuf,
/// Optional path to the output directory.
out_dir_path: Option<PathBuf>,
/// Whether to print result to STDOUT.
#[clap(short, long)]
print_stdout: bool,
}
fn main() -> Result<(), String> {
let opt = Opt::parse();
let input_tree = create_session_if_not_set_then(|s| {
let input_string = s.source_map.load_file(&opt.input_path).expect("failed to open an input file");
Handler::with(|handler| {
let node_builder = NodeBuilder::default();
let input =
leo_parser::parse_program_inputs(handler, &node_builder, &input_string.src, input_string.start_pos)?;
input.to_json_string()
})
.map_err(|e| e.to_string())
})?;
if opt.print_stdout {
println!("{input_tree}");
}
let out_path = if let Some(out_dir) = opt.out_dir_path {
format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
} else {
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
};
fs::write(Path::new(&out_path), input_tree).expect("failed to write output");
Ok(())
}

View File

@ -1,76 +0,0 @@
// Copyright (C) 2019-2023 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 super::*;
use leo_errors::{ParserError, Result};
impl ParserContext<'_> {
/// Returns a [`ParsedInputFile`] struct filled with the data acquired in the file.
pub(crate) fn parse_input_file(&mut self) -> Result<InputAst> {
// Allow underscores in identifiers for input record declarations.
self.allow_identifier_underscores = true;
let mut sections = Vec::new();
while self.has_next() {
if self.check(&Token::LeftSquare) {
sections.push(self.parse_section()?);
} else {
return Err(ParserError::unexpected_token(self.token.token.clone(), self.token.span).into());
}
}
// Do not allow underscores in identifiers outside of input files.
self.allow_identifier_underscores = false;
Ok(InputAst { sections })
}
/// Parses particular section in the Input or State file.
/// `
/// [<identifier>]
/// <...definition>
/// `
/// Returns [`Section`].
fn parse_section(&mut self) -> Result<Section> {
self.expect(&Token::LeftSquare)?;
let section = self.expect_identifier()?;
self.expect(&Token::RightSquare)?;
let mut definitions = Vec::new();
while let Token::Constant | Token::Public | Token::Identifier(_) = self.token.token {
definitions.push(self.parse_input_definition()?);
}
Ok(Section { name: section.name, span: section.span, definitions })
}
/// Parses a single parameter definition:
/// `<identifier> : <type> = <expression>;`
/// Returns [`Definition`].
fn parse_input_definition(&mut self) -> Result<Definition> {
let mode = self.parse_mode()?;
let name = self.expect_identifier()?;
self.expect(&Token::Colon)?;
let (type_, span) = self.parse_type()?;
self.expect(&Token::Assign)?;
let value = self.parse_unary_expression()?;
self.expect(&Token::Semicolon)?;
Ok(Definition { mode, name, type_, value, span })
}
}

View File

@ -34,7 +34,6 @@ pub(super) use context::ParserContext;
mod expression;
mod file;
mod input;
mod statement;
pub(super) mod type_;
@ -44,15 +43,3 @@ pub fn parse(handler: &Handler, node_builder: &NodeBuilder, source: &str, start_
tokens.parse_program()
}
/// Parses an input file at the given file `path` and `source` code text.
pub fn parse_input(
handler: &Handler,
node_builder: &NodeBuilder,
source: &str,
start_pos: BytePos,
) -> Result<InputAst> {
let mut tokens = ParserContext::new(handler, node_builder, crate::tokenize(source, start_pos)?);
tokens.parse_input_file()
}

View File

@ -17,8 +17,9 @@
use super::*;
use leo_ast::{NodeBuilder, Struct, Stub};
use leo_compiler::{Compiler, CompilerOptions, InputAst, OutputOptions};
use leo_compiler::{Compiler, CompilerOptions, OutputOptions};
use leo_package::{build::BuildDirectory, inputs::InputFile, outputs::OutputsDirectory, source::SourceDirectory};
use leo_span::{symbol::with_session_globals, Symbol};
use snarkvm::{