wip need to finish external inputs

This commit is contained in:
collin 2022-09-20 18:26:22 -07:00
parent 368d4c530c
commit 48530523d9
9 changed files with 144 additions and 49 deletions

View File

@ -0,0 +1,46 @@
// 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, Mode, Node, Type};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// A function output from an external program with type record.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct External {
/// The name of the external program.
pub external: Identifier,
/// The name of the external record type.
pub record: Identifier,
/// The parameters span from any annotations to its type.
pub span: Span,
}
impl External {
pub fn get_type(&self) -> Type {
Type::Identifier(self.record.clone())
}
}
impl fmt::Display for External {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.leo/{}.record", self.external, self.record)
}
}
crate::simple_node_impl!(FunctionOutputExternal);

View File

@ -14,14 +14,48 @@
// 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, Mode, Node, Type};
use crate::{External, Identifier, Mode, Node, Type};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Input {
Internal(FunctionInput),
External(External),
}
impl fmt::Display for Input {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Input::*;
match self {
Internal(input) => input.fmt(f),
External(input) => input.fmt(f),
}
}
}
impl Node for Input {
fn span(&self) -> Span {
use Input::*;
match self {
Internal(input) => input.span(),
External(input) => input.span(),
}
}
fn set_span(&mut self, span: Span) {
use Input::*;
match self {
Internal(input) => input.set_span(span),
External(input) => input.set_span(span),
}
}
}
/// A function parameter.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionInput {
/// The name the parameter is accessible as in the function's body.
pub identifier: Identifier,

View File

@ -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, Mode, Node, Type};
use crate::{External, Identifier, Mode, Node, Type};
use leo_span::Span;
use serde::{Deserialize, Serialize};
@ -23,7 +23,7 @@ use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Output {
Internal(FunctionOutput),
External(FunctionOutputExternal),
External(External),
}
impl fmt::Display for Output {
@ -72,28 +72,3 @@ impl fmt::Display for FunctionOutput {
}
crate::simple_node_impl!(FunctionOutput);
/// A function output from an external program with type record.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionOutputExternal {
/// The name of the external program.
pub external: Identifier,
/// The name of the external record type.
pub record: Identifier,
/// The parameters span from any annotations to its type.
pub span: Span,
}
impl FunctionOutputExternal {
pub fn get_type(&self) -> Type {
Type::Identifier(self.record.clone())
}
}
impl fmt::Display for FunctionOutputExternal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.leo/{}.record", self.external, self.record)
}
}
crate::simple_node_impl!(FunctionOutputExternal);

View File

@ -17,6 +17,9 @@
pub mod annotation;
pub use annotation::*;
pub mod external;
pub use external::*;
pub mod finalize;
pub use finalize::*;
@ -43,7 +46,7 @@ pub struct Function {
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// The function's input parameters.
pub input: Vec<FunctionInput>,
pub input: Vec<Input>,
/// The function's output declarations.
pub output: Vec<Output>,
/// The function's output type.
@ -69,7 +72,7 @@ impl Function {
pub fn new(
annotations: Vec<Annotation>,
identifier: Identifier,
input: Vec<FunctionInput>,
input: Vec<Input>,
output: Vec<Output>,
block: Block,
finalize: Option<Finalize>,

View File

@ -363,7 +363,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
}
fn reconstruct_import(&mut self, input: Program) -> Program {
input
self.reconstruct_program(input)
}
fn reconstruct_mapping(&mut self, input: Mapping) -> Mapping {

View File

@ -295,6 +295,31 @@ impl ParserContext<'_> {
})
}
/// Returns a [`Input`] AST node if the next tokens represent a function output.
fn parse_input(&mut self) -> Result<functions::Input> {
if self.peek_is_external() {
let external = self.expect_identifier()?;
let mut span = external.span;
// Parse `.leo/`.
self.eat(&Token::Dot);
self.eat(&Token::Leo);
self.eat(&Token::Div);
// Parse record name.
let record = self.expect_identifier()?;
// Parse `.record`.
self.eat(&Token::Dot);
self.eat(&Token::Record);
span = span + self.prev_token.span;
Ok(functions::Input::External(External { external, record, span }))
} else {
Ok(functions::Input::Internal(self.parse_function_input()?))
}
}
/// Returns a [`FunctionOutput`] AST node if the next tokens represent a function output.
fn parse_function_output(&mut self) -> Result<FunctionOutput> {
// TODO: Could this span be made more accurate?
@ -303,7 +328,7 @@ impl ParserContext<'_> {
Ok(FunctionOutput { mode, type_, span })
}
/// Returns a [`FunctionOutput`] AST node if the next tokens represent a function output.
/// Returns a [`Output`] AST node if the next tokens represent a function output.
fn parse_output(&mut self) -> Result<Output> {
if self.peek_is_external() {
let external = self.expect_identifier()?;
@ -322,7 +347,7 @@ impl ParserContext<'_> {
self.eat(&Token::Record);
span = span + self.prev_token.span;
Ok(Output::External(FunctionOutputExternal { external, record, span }))
Ok(Output::External(External { external, record, span }))
} else {
Ok(Output::Internal(self.parse_function_output()?))
}
@ -374,7 +399,7 @@ impl ParserContext<'_> {
let name = self.expect_identifier()?;
// Parse parameters.
let (inputs, ..) = self.parse_paren_comma_list(|p| p.parse_function_input().map(Some))?;
let (inputs, ..) = self.parse_paren_comma_list(|p| p.parse_input().map(Some))?;
// Parse return type.
let output = match self.eat(&Token::Arrow) {

View File

@ -16,7 +16,7 @@
use crate::CodeGenerator;
use leo_ast::{Circuit, CircuitMember, Function, Identifier, Mapping, Mode, Program, Type};
use leo_ast::{functions, Circuit, CircuitMember, Function, Identifier, Mapping, Mode, Program, Type};
use indexmap::IndexMap;
use itertools::Itertools;
@ -185,14 +185,22 @@ impl<'a> CodeGenerator<'a> {
let register_string = format!("r{}", self.next_register);
self.next_register += 1;
self.variable_mapping
.insert(&input.identifier.name, register_string.clone());
let type_string = match input {
functions::Input::Internal(input) => {
self.variable_mapping
.insert(&input.identifier.name, register_string.clone());
let visibility = match (self.is_program_function, input.mode) {
(true, Mode::None) => Mode::Private,
_ => input.mode,
let visibility = match (self.is_program_function, input.mode) {
(true, Mode::None) => Mode::Private,
_ => input.mode,
};
self.visit_type_with_visibility(&input.type_, visibility)
}
functions::Input::External(input) => {
format!("{}.aleo/{}.record", input.external, input.record)
}
};
let type_string = self.visit_type_with_visibility(&input.type_, visibility);
writeln!(function_string, " input {} as {};", register_string, type_string,)
.expect("failed to write to string");
}

View File

@ -92,7 +92,11 @@ impl ProgramConsumer for StaticSingleAssigner {
network: input.network,
expected_input: input.expected_input,
// TODO: Do inputs need to be processed? They are not processed in the existing compiler.
imports: input.imports,
imports: input
.imports
.into_iter()
.map(|(name, import)| (name, self.consume_program(import)))
.collect(),
functions: input
.functions
.into_iter()

View File

@ -16,7 +16,7 @@ function initialize_board(
destroyer: u64,
// The address of the opponent.
player: address,
) -> board_state {
) -> board.leo/board_state.record {
// Verify that each individual ship placement bitstring is valid.
let valid_carrier: bool = verify.leo/validate_ship(carrier, 5u64, 31u64, 4311810305u64);
console.assert(valid_carrier);
@ -31,10 +31,10 @@ function initialize_board(
console.assert(valid_destroyer);
// Create the board with all the ship placements combined.
let board: u64 = board.leo/create_board(carrier, battleship, cruiser, destroyer);
let board: u64 = verify.leo/create_board(carrier, battleship, cruiser, destroyer);
// Initialize the board state record.
let state: board_state = verify.leo/new_board_state(board, player);
let state: board_state = board.leo/new_board_state(board, player);
return state;
}
@ -46,7 +46,7 @@ function initialize_board(
function offer_battleship(
// The board record to start a game with.
board: board_state,
) -> (board_state, move) {
) -> (board.leo/board_state.record, move.leo/move.record) {
let state: board_state = board.leo/start_board(board);
let dummy: move = move.leo/start_game(board.player_2);
@ -61,7 +61,7 @@ function start_battleship(
board: board_state,
// The move record to play to begin the game. This should be the dummy move record created from offer_battleship.
move_start: move,
) -> (board_state, move) {
) -> (board.leo/board_state.record, move.leo/move.record) {
// Validate that the move players and board players match each other.
console.assert_eq(board.player_1, move_start.player_1);
console.assert_eq(board.player_2, move_start.player_2);
@ -82,7 +82,7 @@ function play(
move_incoming: move,
// The u64 equivalent of the bitwise representation of the next coordinate to play on the opponent's board.
shoot: u64,
) -> (board_state, move) {
) -> (board.leo/board_state.record, move.leo/move.record) {
// Verify the board has been started. This prevents players from starting a game and then creating
// a brand new board to play with.
console.assert(board.game_started);