import codegen working

This commit is contained in:
collin 2022-07-15 23:36:36 -07:00
parent 776ad7c88e
commit 7f14e02055
10 changed files with 80 additions and 66 deletions

View File

@ -1,38 +0,0 @@
// Copyright (C) 2019-2022 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::{Identifier, Node};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// An import statement `import foo.leo;`.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct ImportStatement {
/// The import name `foo` without `.leo` extension.
pub identifier: Identifier,
/// The span including the semicolon.
pub span: Span,
}
impl fmt::Display for ImportStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "import {}.leo;", self.identifier)
}
}
crate::simple_node_impl!(ImportStatement);

View File

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

View File

@ -291,7 +291,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
input
}
fn reconstruct_import(&mut self, input: ImportStatement) -> ImportStatement {
fn reconstruct_import(&mut self, input: Program) -> Program {
input
}
}

View File

@ -192,5 +192,7 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_circuit(&mut self, _input: &'a Circuit) {}
fn visit_import(&mut self, _input: &'a ImportStatement) {}
fn visit_import(&mut self, input: &'a Program) {
self.visit_program(input)
}
}

View File

@ -17,7 +17,7 @@
//! A Leo program consists of import, circuit, and function definitions.
//! Each defined type consists of ast statements and expressions.
use crate::{Circuit, Function, FunctionInput, Identifier, ImportStatement};
use crate::{Circuit, Function, FunctionInput, Identifier};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
@ -34,7 +34,7 @@ pub struct Program {
/// Empty after parsing.
pub expected_input: Vec<FunctionInput>,
/// A map from import names to import definitions.
pub imports: IndexMap<Identifier, ImportStatement>,
pub imports: IndexMap<Identifier, Program>,
/// A map from function names to function definitions.
pub functions: IndexMap<Identifier, Function>,
/// A map from circuit names to circuit definitions.
@ -43,9 +43,8 @@ pub struct Program {
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (_, import) in self.imports.iter() {
import.fmt(f)?;
writeln!(f,)?;
for (id, _import) in self.imports.iter() {
writeln!(f, "import {}.leo;", id)?;
}
for (_, function) in self.functions.iter() {
function.fmt(f)?;

View File

@ -15,9 +15,13 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use super::*;
use leo_errors::{ParserError, ParserWarning, Result};
use crate::parse_ast;
use leo_errors::{CompilerError, ParserError, ParserWarning, Result};
use leo_span::source_map::FileName;
use leo_span::sym;
use leo_span::symbol::with_session_globals;
use std::fs;
impl ParserContext<'_> {
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
@ -71,25 +75,50 @@ impl ParserContext<'_> {
}
/// Parses an import statement `import foo.leo;`.
pub(super) fn parse_import(&mut self) -> Result<(Identifier, ImportStatement)> {
let start = self.expect(&Token::Import)?;
pub(super) fn parse_import(&mut self) -> Result<(Identifier, Program)> {
// Parse `import`.
let _start = self.expect(&Token::Import)?;
// Parse `foo`.
let import_name = self.expect_identifier()?;
// Parse `.leo`.
self.expect(&Token::Dot)?;
let leo_file_extension = self.expect_identifier()?;
// Throw error for non-leo files.
if leo_file_extension.name.ne(&sym::leo) {
return Err(ParserError::leo_imports_only(leo_file_extension, self.token.span).into());
}
let end = self.expect(&Token::Semicolon)?;
let _end = self.expect(&Token::Semicolon)?;
Ok((
import_name,
ImportStatement {
identifier: import_name,
span: start + end,
},
))
// Tokenize and parse import file.
// Todo: move this to a different module.
let mut import_file_path =
std::env::current_dir().map_err(|err| CompilerError::cannot_open_cwd(err, self.token.span))?;
import_file_path.push("imports");
import_file_path.push(format!("{}.leo", import_name.name));
// Throw an error if the import file doesn't exist.
if !import_file_path.exists() {
return Err(CompilerError::import_not_found(import_file_path.display(), self.token.span).into());
}
// Read the import file into string.
// Todo: protect against cyclic imports.
let program_string =
fs::read_to_string(&import_file_path).map_err(|e| CompilerError::file_read_error(&import_file_path, e))?;
// Create import file name.
let name: FileName = FileName::Real(import_file_path);
// Register the source (`program_string`) in the source map.
let prg_sf = with_session_globals(|s| s.source_map.new_source(&program_string, name));
// Use the parser to construct the imported abstract syntax tree (ast).
let program_ast = parse_ast(self.handler, &prg_sf.src, prg_sf.start_pos)?;
Ok((import_name, program_ast.into_repr()))
}
/// Returns a [`Vec<CircuitMember>`] AST node if the next tokens represent a circuit member variable

View File

@ -16,7 +16,7 @@
use crate::CodeGenerator;
use leo_ast::{Circuit, CircuitMember, Function, ImportStatement, Program};
use leo_ast::{Circuit, CircuitMember, Function, Identifier, Program};
use indexmap::IndexMap;
use itertools::Itertools;
@ -32,8 +32,8 @@ impl<'a> CodeGenerator<'a> {
program_string.push_str(
&input
.imports
.values()
.map(|import| self.visit_import(import))
.iter()
.map(|(identifier, imported_program)| self.visit_import(identifier, imported_program))
.join("\n"),
);
@ -72,8 +72,13 @@ impl<'a> CodeGenerator<'a> {
program_string
}
fn visit_import(&mut self, import: &'a ImportStatement) -> String {
format!("import {}.aleo;", import.identifier)
fn visit_import(&mut self, import_name: &'a Identifier, import_program: &'a Program) -> String {
// Load symbols into composite mapping.
let _import_program_string = self.visit_program(import_program);
// todo: We do not need the import program string because we generate instructions for imports separately during leo build.
// Generate string for import statement.
format!("import {}.aleo;", import_name)
}
fn visit_circuit_or_record(&mut self, circuit: &'a Circuit) -> String {

View File

@ -57,4 +57,8 @@ impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> {
self.handler.emit_err(err);
}
}
fn visit_import(&mut self, input: &'a Program) {
self.visit_program(input)
}
}

View File

@ -309,7 +309,21 @@ create_messages!(
@formatted
illegal_static_member_assignment {
args: (member: impl Display),
msg: format!("Tried to assign to static member `{}`", member),
msg: format!("Tried to assign to static member `{member}`"),
help: None,
}
@formatted
import_not_found {
args: (file_path: impl Display),
msg: format!("Attempted to import a file that does not exist `{file_path}`."),
help: None,
}
@formatted
cannot_open_cwd {
args: (err: impl ErrorArg),
msg: format!("Failed to open current working directory. Error: {err}"),
help: None,
}
);

View File

@ -2,5 +2,7 @@ import other.leo;
// The 'helloworld' main function.
function main(public a: u32, b: u32) -> u32 {
let o: Other = Other { a: 1u64 };
return a + b;
}