Merge with testnet3.

This commit is contained in:
Alessandro Coglio 2022-09-21 13:33:56 -07:00
commit 4002ad8215
424 changed files with 3649 additions and 2079 deletions

View File

@ -16,7 +16,7 @@
use super::*;
/// A function call expression, e.g., `foo(args)` or `Foo::bar(args)`.
/// A function call expression, e.g.`foo(args)` or `Foo::bar(args)`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CallExpression {
/// An expression evaluating to a callable function,
@ -24,13 +24,23 @@ pub struct CallExpression {
pub function: Box<Expression>, // todo: make this identifier?
/// Expressions for the arguments passed to the functions parameters.
pub arguments: Vec<Expression>,
/// The name of the external program call, e.g.`bar` in `bar.leo`.
pub external: Option<Box<Expression>>,
/// Span of the entire call `function(arguments)`.
pub span: Span,
}
impl fmt::Display for CallExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.external {
Some(external) => {
write!(f, "{}.leo/{}(", external, self.function)?;
}
None => {
write!(f, "{}(", self.function)?;
}
}
for (i, param) in self.arguments.iter().enumerate() {
write!(f, "{}", param)?;
if i < self.arguments.len() - 1 {

View File

@ -0,0 +1,52 @@
// 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, 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 the parameter is accessible as in the function's body.
pub identifier: Identifier,
/// The name of the external program.
pub program_name: 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 type_(&self) -> Type {
Type::Identifier(self.record)
}
}
impl fmt::Display for External {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}: {}.leo/{}.record",
self.identifier, self.program_name, self.record
)
}
}
crate::simple_node_impl!(External);

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::{Block, FunctionInput, FunctionOutput, Identifier, Node, Tuple, Type};
use crate::{Block, Identifier, Input, Node, Output, Tuple, Type};
use leo_span::Span;
@ -27,9 +27,9 @@ pub struct Finalize {
/// The finalize identifier.
pub identifier: Identifier,
/// The finalize block's input parameters.
pub input: Vec<FunctionInput>,
pub input: Vec<Input>,
/// The finalize blocks's output declaration.
pub output: Vec<FunctionOutput>,
pub output: Vec<Output>,
/// The finalize block's output type.
pub output_type: Type,
/// The body of the function.
@ -40,17 +40,11 @@ pub struct Finalize {
impl Finalize {
/// Create a new finalize block.
pub fn new(
identifier: Identifier,
input: Vec<FunctionInput>,
output: Vec<FunctionOutput>,
block: Block,
span: Span,
) -> Self {
pub fn new(identifier: Identifier, input: Vec<Input>, output: Vec<Output>, block: Block, span: Span) -> Self {
let output_type = match output.len() {
0 => Type::Unit,
1 => output[0].type_.clone(),
_ => Type::Tuple(Tuple(output.iter().map(|output| output.type_.clone()).collect())),
1 => output[0].type_(),
_ => Type::Tuple(Tuple(output.iter().map(|output| output.type_()).collect())),
};
Self {

View File

@ -14,14 +14,74 @@
// 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 Input {
pub fn type_(&self) -> Type {
use Input::*;
match self {
Internal(input) => input.type_.clone(),
External(input) => input.type_(),
}
}
pub fn identifier(&self) -> Identifier {
use Input::*;
match self {
Internal(input) => input.identifier,
External(input) => input.identifier,
}
}
pub fn mode(&self) -> Mode {
use Input::*;
match self {
Internal(input) => input.mode,
External(_) => Mode::None,
}
}
}
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,14 +14,64 @@
// 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::{Mode, Node, Type};
use crate::{External, Mode, Node, Type};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// A function parameter.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Output {
Internal(FunctionOutput),
External(External),
}
impl Output {
pub fn type_(&self) -> Type {
match self {
Output::Internal(output) => output.type_.clone(),
Output::External(output) => output.type_(),
}
}
pub fn mode(&self) -> Mode {
match self {
Output::Internal(output) => output.mode,
Output::External(_) => Mode::None,
}
}
}
impl fmt::Display for Output {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Output::*;
match self {
Internal(output) => output.fmt(f),
External(output) => output.fmt(f),
}
}
}
impl Node for Output {
fn span(&self) -> Span {
use Output::*;
match self {
Internal(output) => output.span(),
External(output) => output.span(),
}
}
fn set_span(&mut self, span: Span) {
use Output::*;
match self {
Internal(output) => output.set_span(span),
External(output) => output.set_span(span),
}
}
}
/// A function output.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionOutput {
/// The mode of the function output.
pub mode: Mode,

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,9 +46,9 @@ 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<FunctionOutput>,
pub output: Vec<Output>,
/// The function's output type.
pub output_type: Type,
/// The body of the function.
@ -69,17 +72,22 @@ impl Function {
pub fn new(
annotations: Vec<Annotation>,
identifier: Identifier,
input: Vec<FunctionInput>,
output: Vec<FunctionOutput>,
input: Vec<Input>,
output: Vec<Output>,
block: Block,
finalize: Option<Finalize>,
span: Span,
) -> Self {
// Determine the output type of the function
let get_output_type = |output: &Output| match &output {
Output::Internal(output) => output.type_.clone(),
Output::External(output) => output.type_(),
};
let output_type = match output.len() {
0 => Type::Unit,
1 => output[0].type_.clone(),
_ => Type::Tuple(Tuple(output.iter().map(|output| output.type_.clone()).collect())),
1 => get_output_type(&output[0]),
_ => Type::Tuple(Tuple(output.iter().map(|output| get_output_type(output)).collect())),
};
Function {

View File

@ -21,11 +21,11 @@ use leo_errors::{AstError, Result};
/// Input data which includes [`ProgramInput`].
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Input {
pub struct InputData {
pub program_input: ProgramInput,
}
impl Input {
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))?)

View File

@ -91,6 +91,7 @@ pub trait ExpressionReconstructor {
.into_iter()
.map(|arg| self.reconstruct_expression(arg).0)
.collect(),
external: input.external,
span: input.span,
}),
Default::default(),
@ -362,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

@ -31,7 +31,7 @@ pub(crate) use tokenizer::*;
pub mod parser;
pub use parser::*;
use leo_ast::{Ast, Input, ProgramInput};
use leo_ast::{input::InputData, Ast, ProgramInput};
use leo_errors::emitter::Handler;
use leo_errors::Result;
@ -44,8 +44,8 @@ pub fn parse_ast(handler: &Handler, source: &str, start_pos: BytePos) -> Result<
}
/// Parses program inputs from from the input file path and state file path
pub fn parse_program_inputs(handler: &Handler, input_string: &str, start_pos: BytePos) -> Result<Input> {
pub fn parse_program_inputs(handler: &Handler, input_string: &str, start_pos: BytePos) -> Result<InputData> {
let program_input: ProgramInput = parser::parse_input(handler, input_string, start_pos)?.try_into()?;
Ok(Input { program_input })
Ok(InputData { program_input })
}

View File

@ -364,6 +364,21 @@ impl ParserContext<'_> {
index,
span,
}))
} else if self.eat(&Token::Leo) {
// Eat an external function call.
self.eat(&Token::Div); // todo: Make `/` a more general token.
// Parse function name.
let name = self.expect_identifier()?;
// Parse the function call.
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
expr = Expression::Call(CallExpression {
span: expr.span() + span,
function: Box::new(Expression::Identifier(name)),
external: Some(Box::new(expr)),
arguments,
});
} else {
// Parse identifier name.
let name = self.expect_identifier()?;
@ -389,6 +404,7 @@ impl ParserContext<'_> {
expr = Expression::Call(CallExpression {
span: expr.span() + span,
function: Box::new(expr),
external: None,
arguments,
});
}

View File

@ -18,8 +18,8 @@ use super::*;
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 leo_span::{sym, Symbol};
use std::fs;
@ -95,12 +95,11 @@ impl ParserContext<'_> {
// Parse `.leo`.
self.expect(&Token::Dot)?;
let leo_file_extension = self.expect_identifier()?;
if !self.eat(&Token::Leo) {
// 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());
return Err(ParserError::leo_imports_only(self.token.span).into());
}
let _end = self.expect(&Token::Semicolon)?;
// Tokenize and parse import file.
@ -284,16 +283,45 @@ impl ParserContext<'_> {
}
}
/// Returns a [`FunctionInput`] AST node if the next tokens represent a function parameter.
fn parse_function_input(&mut self) -> Result<FunctionInput> {
/// Returns a [`Input`] AST node if the next tokens represent a function output.
fn parse_input(&mut self) -> Result<functions::Input> {
let mode = self.parse_mode()?;
let (name, type_) = self.parse_typed_ident()?;
Ok(FunctionInput {
let name = self.expect_identifier()?;
self.expect(&Token::Colon)?;
if self.peek_is_external() {
let external = self.expect_identifier()?;
let mut span = name.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 {
identifier: name,
program_name: external,
record,
span,
}))
} else {
let type_ = self.parse_type()?.0;
Ok(functions::Input::Internal(FunctionInput {
identifier: name,
mode,
type_,
span: name.span,
})
}))
}
}
/// Returns a [`FunctionOutput`] AST node if the next tokens represent a function output.
@ -304,6 +332,43 @@ impl ParserContext<'_> {
Ok(FunctionOutput { mode, type_, span })
}
/// 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()?;
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(Output::External(External {
identifier: Identifier::new(Symbol::intern("dummy")),
program_name: external,
record,
span,
}))
} else {
Ok(Output::Internal(self.parse_function_output()?))
}
}
fn peek_is_external(&self) -> bool {
matches!(
(&self.token.token, self.look_ahead(1, |t| &t.token)),
(Token::Identifier(_), Token::Dot)
)
}
/// Returns `true` if the next token is Function or if it is a Const followed by Function.
/// Returns `false` otherwise.
fn peek_is_function(&self) -> bool {
@ -343,7 +408,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) {
@ -351,8 +416,8 @@ impl ParserContext<'_> {
true => {
self.disallow_circuit_construction = true;
let output = match self.peek_is_left_par() {
true => self.parse_paren_comma_list(|p| p.parse_function_output().map(Some))?.0,
false => vec![self.parse_function_output()?],
true => self.parse_paren_comma_list(|p| p.parse_output().map(Some))?.0,
false => vec![self.parse_output()?],
};
self.disallow_circuit_construction = false;
output
@ -373,7 +438,7 @@ impl ParserContext<'_> {
let identifier = self.expect_identifier()?;
// Parse parameters.
let (input, ..) = self.parse_paren_comma_list(|p| p.parse_function_input().map(Some))?;
let (input, ..) = self.parse_paren_comma_list(|p| p.parse_input().map(Some))?;
// Parse return type.
let output = match self.eat(&Token::Arrow) {
@ -381,8 +446,8 @@ impl ParserContext<'_> {
true => {
self.disallow_circuit_construction = true;
let output = match self.peek_is_left_par() {
true => self.parse_paren_comma_list(|p| p.parse_function_output().map(Some))?.0,
false => vec![self.parse_function_output()?],
true => self.parse_paren_comma_list(|p| p.parse_output().map(Some))?.0,
false => vec![self.parse_output()?],
};
self.disallow_circuit_construction = false;
output

View File

@ -20,7 +20,7 @@ use leo_errors::{ParserError, Result};
impl ParserContext<'_> {
/// Returns a [`ParsedInputFile`] struct filled with the data acquired in the file.
pub(crate) fn parse_input(&mut self) -> Result<InputAst> {
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();

View File

@ -50,5 +50,5 @@ pub fn parse(handler: &Handler, source: &str, start_pos: BytePos) -> Result<Prog
pub fn parse_input(handler: &Handler, source: &str, start_pos: BytePos) -> Result<InputAst> {
let mut tokens = ParserContext::new(handler, crate::tokenize(source, start_pos)?);
tokens.parse_input()
tokens.parse_input_file()
}

View File

@ -214,7 +214,7 @@ impl Namespace for InputNamespace {
}
fn run_test(&self, test: Test) -> Result<Value, String> {
create_session_if_not_set_then(|s| with_handler(tokenize(test, s)?, |p| p.parse_input()).map(yaml_or_fail))
create_session_if_not_set_then(|s| with_handler(tokenize(test, s)?, |p| p.parse_input_file()).map(yaml_or_fail))
}
}

View File

@ -417,6 +417,7 @@ impl Token {
"increment" => Token::Increment,
"import" => Token::Import,
"let" => Token::Let,
"leo" => Token::Leo,
"mapping" => Token::Mapping,
"public" => Token::Public,
"record" => Token::Record,

View File

@ -130,6 +130,8 @@ pub enum Token {
Return,
SelfLower,
Static,
// For imports.
Leo,
// Meta Tokens
Eof,
@ -213,6 +215,7 @@ impl Token {
Token::Increment => sym::increment,
Token::Import => sym::import,
Token::Let => sym::Let,
Token::Leo => sym::leo,
Token::Mapping => sym::mapping,
Token::Public => sym::Public,
Token::Record => sym::record,
@ -335,6 +338,7 @@ impl fmt::Display for Token {
Public => write!(f, "public"),
Return => write!(f, "return"),
Static => write!(f, "static"),
Leo => write!(f, "leo"),
Eof => write!(f, "<eof>"),
}
}

View File

@ -276,7 +276,10 @@ impl<'a> CodeGenerator<'a> {
}
fn visit_call(&mut self, input: &'a CallExpression) -> (String, String) {
let mut call_instruction = format!(" call {} ", input.function);
let mut call_instruction = match &input.external {
Some(external) => format!(" call {}.aleo/{} ", external, input.function),
None => format!(" call {} ", input.function),
};
let mut instructions = String::new();
for argument in input.arguments.iter() {

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,23 @@ impl<'a> CodeGenerator<'a> {
let register_string = format!("r{}", self.next_register);
self.next_register += 1;
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 type_string = self.visit_type_with_visibility(&input.type_, visibility);
self.visit_type_with_visibility(&input.type_, visibility)
}
functions::Input::External(input) => {
self.variable_mapping
.insert(&input.identifier.name, register_string.clone());
format!("{}.aleo/{}.record", input.program_name, input.record)
}
};
writeln!(function_string, " input {} as {};", register_string, type_string,)
.expect("failed to write to string");
}
@ -219,16 +228,25 @@ impl<'a> CodeGenerator<'a> {
let register_string = format!("r{}", self.next_register);
self.next_register += 1;
// TODO: Dedup code.
let type_string = match input {
functions::Input::Internal(input) => {
self.variable_mapping
.insert(&input.identifier.name, register_string.clone());
// A finalize block defaults to public visibility.
let visibility = match (self.is_program_function, input.mode) {
(true, Mode::None) => Mode::Public,
(true, mode) => mode,
_ => unreachable!("Only program functions can have finalize blocks."),
_ => input.mode,
};
let type_string = self.visit_type_with_visibility(&input.type_, visibility);
self.visit_type_with_visibility(&input.type_, visibility)
}
functions::Input::External(input) => {
self.variable_mapping
.insert(&input.program_name.name, register_string.clone());
format!("{}.aleo/{}.record", input.program_name, input.record)
}
};
writeln!(function_string, " input {} as {};", register_string, type_string,)
.expect("failed to write to string");
}

View File

@ -18,8 +18,8 @@ use crate::CodeGenerator;
use leo_ast::{
AssignStatement, Block, ConditionalStatement, ConsoleFunction, ConsoleStatement, DecrementStatement,
DefinitionStatement, Expression, FinalizeStatement, IncrementStatement, IterationStatement, Mode, ReturnStatement,
Statement,
DefinitionStatement, Expression, FinalizeStatement, IncrementStatement, IterationStatement, Mode, Output,
ReturnStatement, Statement,
};
use itertools::Itertools;
@ -52,6 +52,8 @@ impl<'a> CodeGenerator<'a> {
.into_iter()
.zip(self.current_function.unwrap().output.iter())
.map(|(operand, output)| {
match output {
Output::Internal(output) => {
let visibility = if self.is_program_function {
match self.in_finalize {
// If in finalize block, the default visibility is public.
@ -74,6 +76,14 @@ impl<'a> CodeGenerator<'a> {
operand,
self.visit_type_with_visibility(&output.type_, visibility)
)
}
Output::External(output) => {
format!(
" output {} as {}.aleo/{}.record;\n",
operand, output.program_name, output.record,
)
}
}
})
.join("");

View File

@ -30,8 +30,8 @@ impl ProgramReconstructor for Flattener<'_> {
// Initialize `self.circuits` with the finalize's input as necessary.
self.circuits = Default::default();
for input in &finalize.input {
if let Type::Identifier(circuit_name) = input.type_ {
self.circuits.insert(input.identifier.name, circuit_name.name);
if let Type::Identifier(circuit_name) = input.type_() {
self.circuits.insert(input.identifier().name, circuit_name.name);
}
}
@ -71,8 +71,8 @@ impl ProgramReconstructor for Flattener<'_> {
// Initialize `self.circuits` with the function's input as necessary.
self.circuits = Default::default();
for input in &function.input {
if let Type::Identifier(circuit_name) = input.type_ {
self.circuits.insert(input.identifier.name, circuit_name.name);
if let Type::Identifier(circuit_name) = input.type_() {
self.circuits.insert(input.identifier().name, circuit_name.name);
}
}

View File

@ -133,6 +133,7 @@ impl ExpressionConsumer for StaticSingleAssigner {
function: input.function,
// Consume the arguments.
arguments,
external: input.external,
span: input.span,
}));
statements.push(statement);

View File

@ -30,7 +30,7 @@ impl FunctionConsumer for StaticSingleAssigner {
// However, for each input, we must add each symbol to the rename table.
for input_variable in function.input.iter() {
self.rename_table
.update(input_variable.identifier.name, input_variable.identifier.name);
.update(input_variable.identifier().name, input_variable.identifier().name);
}
let block = Block {
@ -49,7 +49,7 @@ impl FunctionConsumer for StaticSingleAssigner {
// However, for each input, we must add each symbol to the rename table.
for input_variable in finalize.input.iter() {
self.rename_table
.update(input_variable.identifier.name, input_variable.identifier.name);
.update(input_variable.identifier().name, input_variable.identifier().name);
}
let block = Block {
@ -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

@ -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 leo_ast::{Function, FunctionInput, Type};
use leo_ast::{Function, Input, Type};
use leo_span::Span;
use crate::SymbolTable;
@ -23,7 +23,7 @@ use crate::SymbolTable;
#[derive(Debug, Clone)]
pub struct FinalizeData {
/// The inputs to the finalize block.
pub(crate) input: Vec<FunctionInput>,
pub(crate) input: Vec<Input>,
/// The output type of the finalize block.
pub(crate) output_type: Type,
}
@ -38,7 +38,7 @@ pub struct FunctionSymbol {
/// The `Span` associated with the function.
pub(crate) span: Span,
/// The inputs to the function.
pub(crate) input: Vec<FunctionInput>,
pub(crate) input: Vec<Input>,
/// Metadata associated with the finalize block.
pub(crate) finalize: Option<FinalizeData>,
}

View File

@ -456,7 +456,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
.iter()
.zip(input.arguments.iter())
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_.clone()));
self.visit_expression(argument, &Some(expected.type_()));
});
Some(ret)

View File

@ -140,28 +140,28 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Type check the function's parameters.
function.input.iter().for_each(|input_var| {
// Check that the type of input parameter is valid.
self.assert_type_is_valid(input_var.span, &input_var.type_);
self.assert_not_tuple(input_var.span, &input_var.type_);
self.assert_type_is_valid(input_var.span(), &input_var.type_());
self.assert_not_tuple(input_var.span(), &input_var.type_());
match self.is_program_function {
// If the function is a program function, then check that the parameter mode is not a constant.
true if input_var.mode == Mode::Const => self.emit_err(
TypeCheckerError::program_function_inputs_cannot_be_const(input_var.span),
true if input_var.mode() == Mode::Const => self.emit_err(
TypeCheckerError::program_function_inputs_cannot_be_const(input_var.span()),
),
// If the function is not a program function, then check that the parameters do not have an associated mode.
false if input_var.mode != Mode::None => self.emit_err(
TypeCheckerError::helper_function_inputs_cannot_have_modes(input_var.span),
false if input_var.mode() != Mode::None => self.emit_err(
TypeCheckerError::helper_function_inputs_cannot_have_modes(input_var.span()),
),
_ => {} // Do nothing.
}
// Check for conflicting variable names.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
input_var.identifier.name,
input_var.identifier().name,
VariableSymbol {
type_: input_var.type_.clone(),
span: input_var.identifier.span(),
declaration: VariableType::Input(input_var.mode),
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
},
) {
self.handler.emit_err(err);
@ -170,6 +170,9 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Type check the function's return type.
function.output.iter().for_each(|output_type| {
match output_type {
Output::External(_) => {} // Do not type check external record function outputs.
Output::Internal(output_type) => {
// Check that the type of output is valid.
self.assert_type_is_valid(output_type.span, &output_type.type_);
@ -177,6 +180,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
if output_type.mode == Mode::Const {
self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(output_type.span));
}
}
}
});
self.visit_block(&function.block);
@ -226,21 +231,21 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
finalize.input.iter().for_each(|input_var| {
// Check that the type of input parameter is valid.
self.assert_type_is_valid(input_var.span, &input_var.type_);
self.assert_not_tuple(input_var.span, &input_var.type_);
self.assert_type_is_valid(input_var.span(), &input_var.type_());
self.assert_not_tuple(input_var.span(), &input_var.type_());
// Check that the input parameter is not constant or private.
if input_var.mode == Mode::Const || input_var.mode == Mode::Private {
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span));
if input_var.mode() == Mode::Const || input_var.mode() == Mode::Private {
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
}
// Check for conflicting variable names.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
input_var.identifier.name,
input_var.identifier().name,
VariableSymbol {
type_: input_var.type_.clone(),
span: input_var.identifier.span(),
declaration: VariableType::Input(input_var.mode),
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
},
) {
self.handler.emit_err(err);
@ -250,11 +255,11 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Type check the function's return type.
finalize.output.iter().for_each(|output_type| {
// Check that the type of output is valid.
self.assert_type_is_valid(output_type.span, &output_type.type_);
self.assert_type_is_valid(output_type.span(), &output_type.type_());
// Check that the mode of the output is valid.
if output_type.mode == Mode::Const {
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(output_type.span));
if output_type.mode() == Mode::Const {
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(output_type.span()));
}
});

View File

@ -239,7 +239,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
.iter()
.zip(input.arguments.iter())
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_.clone()));
self.visit_expression(argument, &Some(expected.type_()));
});
}
}

View File

@ -249,8 +249,8 @@ create_messages!(
@formatted
leo_imports_only {
args: (name: impl Display),
msg: format!("Invalid import call to non-leo file `{name}`."),
args: (),
msg: "Invalid import call to non-leo file.",
help: Some("Only imports of Leo `.leo` files are currently supported.".to_string()),
}

2
examples/battleship/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
outputs/
build/

View File

@ -0,0 +1,923 @@
# Leo Battleship 🏴‍☠️
- [Summary](#summary)
- [Build](#how-to-build)
- [Run](#how-to-run)
- [1. Setup](#1-setup)
- [2. Select Player 1's Board](#2-select-player-1s-board)
- [3. Pass to Player 2](#3-pass-to-player-2)
- [4. Select Player 2's Board](#4-select-player-2s-board)
- [5. Pass to Player 1](#5-pass-to-player-1)
- [6. Player 1 Shoots First](#6-player-1-shoots-first)
- [7. Player 2 Shoots Second](#7-player-2-shoots-second)
- [8. Player 1 Shoots Third](#8-player-1-shoots-third)
- [9. Player 2 Shoots Fourth](#9-player-2-shoots-fourth)
- [10. Who Wins?](#10-who-wins)
- [ZK Battleship Privacy](#zk-battleship-privacy)
- [Modeling the Boards and Ships](#modeling-the-board-and-ships)
- [Validating a Single Ship](#validating-a-single-ship-at-a-time)
- [Validating all Ships](#validating-all-ships-together-in-a-single-board)
- [Sequencing Game State](#ensure-that-players-and-boards-cannot-swap-mid-game)
- [Preventing Double Moves](#ensure-that-each-player-can-only-move-once-before-the-next-player-can-move)
- [Ensuring Valid Moves](#enforce-constraints-on-valid-moves-and-force-the-player-to-give-their-opponent-information-about-their-opponents-previous-move-in-order-to-continue-playing)
- [Winning](#winning-the-game)
# Summary
Battleship is a game where two players lay their ships into secret configurations on their respective 8x8 grids,
and then take turns firing upon each other's board.
The game ends when one player has sunk all of the other player's ships.
This application was translated into Leo from the [zk-battleship](https://github.com/demox-labs/zk-battleship) example written by the Aleo community - show them some love!
## How to Build
To compile this Leo program, run:
```bash
leo build
```
## How to Run
<details><summary>Commands and Playing the Game</summary>
### 1. Setup
In order to play battleship, there must be two players with two boards.
Players will be represented by their Aleo address.
You can use the provided player accounts or [generate your own](https://aleohq.github.io/aleo/).
```markdown
Player 1:
Private Key APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm
View Key AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6
Address aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy
Player 2:
Private Key APrivateKey1zkp86FNGdKxjgAdgQZ967bqBanjuHkAaoRe19RK24ZCGsHH
View Key AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE
Address aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry
```
Save the keys and addresses. Set the `program.json` private_key and address to one of the newly created aleo accounts. We'll refer to this address as Player 1, and the remaining address as Player 2.
```json
{
"program": "battleship.aleo",
"version": "0.0.0",
"description": "Play ZK Battleship",
"development": {
"private_key": "APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm",
"view_key": "AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6",
"address": "aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy"
},
"license": "MIT"
}
```
### 2. Select Player 1's Board
Now, we need to make a board as Player 1.
See the [modeling the boards and ships](#modeling-the-board-and-ships) section for information on valid ship bitstrings and placements on the board.
For this example, we will be using sample valid inputs.
Initialize a new board as Player 1 with valid ship inputs and Player 2's address: `leo run initialize_board ship_5_bitstring ship_4_bitstring ship_3_bitstring ship_2_bitstring player_2_address`
**Run**
```
leo run initialize_board 34084860461056u64 551911718912u64 7u64 1157425104234217472u64 aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry
```
**Output**
```bash
➡️ Output
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: false.private,
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
}
✅ Executed 'battleship.aleo/initialize_board'
```
The output is a board_state record owned by Player 1.
Notice that the `game_started` flag is false, as well as the composite ship configuration `ships`.
1157459741006397447u64 to a binary bitstring becomes `0001000000010000000111111000000010000000100000001000000000000111`,
or laid out in columns and rows:
```
0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 1 1 1 1 1
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1
```
### 3. Pass to Player 2
Now, we can offer a battleship game to player 2. Run `leo run offer_battleship 'board_state.record'` with the record you just created:
**Run**
```
leo run offer_battleship '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: false.private,
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
}'
```
**Output**
```bash
➡️ Outputs
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
}
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
}
✅ Executed 'battleship.aleo/offer_battleship'
```
The first output record is the udpated board_state.record.
Notice the `game_started` flag is now true.
This board cannot be used to offer any other battleship games or accept any battleship game offers.
Player 1 would need to initialize a new board and use that instead.
The second output record is a dummy move.record --
there are no fire coordinates included to play on Player 2's board,
and no information about any previous Player 2 moves (Player 2 has not made any moves yet).
This move.record is owned by Player 2, who must use that in combination with their own board_state.record to accept the game. Let's do that now.
### 4. Select Player 2's Board
We must run the program as Player 2 now, so switch the `program.json` file to use Player 2's keys:
```json
{
"program": "battleship.aleo",
"version": "0.0.0",
"description": "Play ZK Battleship",
"development": {
"private_key": "APrivateKey1zkp86FNGdKxjgAdgQZ967bqBanjuHkAaoRe19RK24ZCGsHH",
"view_key": "AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE",
"address": "aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry"
},
"license": "MIT"
}
```
We'll create a new and different board for Player 2, and make sure to include Player 1's address as the opponent:
**Run**
```bash
leo run initialize_board 31u64 2207646875648u64 224u64 9042383626829824u64 aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy
```
**Output**
```bash
➡️ Output
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: false.private,
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
}
✅ Executed 'battleship.aleo/initialize_board'
```
Note, the output ships here is 9044591273705727u64, which in a bitstring is:
```
0 0 1 0 0 0 0 0
0 0 1 0 0 0 1 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
```
### 5. Pass to Player 1
Now, we can accept Player 1's offer. Run `leo run start_battleship 'board_state.record' 'move.record'`:
**Run**
```bash
leo run start_battleship '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: false.private,
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
}'
```
**Outputs**
```bash
➡️ Outputs
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
}
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 0u64.private,
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
}
✅ Executed 'battleship.aleo/start_battleship'
```
Notice the outputs here are similar to `offer_battleship`.
A dummy move.record is owned by Player 1, and Player 2 gets a board_state.record with the `game_started` flag updated.
However, now that Player 1 has a move.record and a started board, they can begin to play.
### 6. Player 1 Shoots First
**Switch** `program.json`'s keys back to Player 1's.
Player 1 now makes the first real move: `leo run play 'board_state.record' 'move.record' fire_coordinate`
**Run**
```bash
leo run play '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
}' '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 0u64.private,
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
}' 1u64
```
**Outputs**
```bash
➡️ Outputs
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 1u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
}
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 1u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
}
✅ Executed 'battleship.aleo/play'
```
Player 1 has an updated board_state.record -- they have a new `played_tiles` bitstring,
which corresponds to the fire coordinate they just sent to Player 2.
You can see that the `incoming_fire_coordinate` in the move.record owned by Player 2 matches exactly the input given by Player 1.
Player 2 can now play this move tile and respond with a fire coordinate of their own,
and they will also let Player 1 know whether or not Player 1's fire coordinate hit or miss Player 2's ships.
### 7. Player 2 Shoots Second
**Switch** `program.json` to Player 2's keys. Player 2 makes their move:
**Run**
```bash
leo run play '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 1u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
}' 2048u64
```
**Outputs**
```bash
➡️ Outputs
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 2048u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
}
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 2048u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 1u64.private,
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
}
✅ Executed 'battleship.aleo/play'
```
Player 2 now has an updated board_state.record which includes their newly updated `played_tiles`,
only containing the fire coordinate they just sent to Player 1.
Player 1 now owns a new move.record which includes the `hits_and_misses` field.
This contains only the result of Player 1's previous fire coordinate they had sent to Player 2.
It will always be a single coordinate on the 8x8 grid if it's a hit. A miss is 0u64 (8x8 grid of 0s),
whereas a hit is the u64 equivalent of their previous fire coordinate in bitstring form.
If you check Player 2's ships configuration, you'll note their entire bottom row is covered by two ships,
so sample valid hits on the bottom row would be: 1u64, 2u64, 4u64, 8u64, 16u64, 32u64, 64u64, and 128u64.
Since Player 1's first fire coordinate (1u64) was a hit, the `hits_and_misses` field is also 1u64.
Player 1's next move will consume this move.record, which will update Player 1's board with the hit-or-miss,
as well as figure out the result of Player 2's fire coordinate.
Now that Player 1 has some `played_tiles`, they can no longer choose an alread-played fire coordinate.
For example, running `aleo run play 'board_state.record' 'move.record' 1u64` will fail, because 1u64 has already been played.
### 8. Player 1 Shoots Third
**Switch** `program.json` to use Player 1's keys.
**Run**
```bash
leo run play '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 1u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
}' '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 2048u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 1u64.private,
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
}' 2u64
```
**Outputs**
```bash
➡️ Outputs
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 1u64.private,
played_tiles: 3u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 853278652528988609827041334083853520436225751739504321439524466875699631772group.public
}
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 2u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
}
✅ Executed 'battleship.aleo/play'
```
As before, both a board_state.record and move.record are created.
The board_state.record now contains 3u64 as the `played_tiles`, which looks like this in bitstring form:
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
```
The board_state.record `hits_and_misses` field has also been updated with the result of their previous move. The new move.record owned by Player 2 now contains information about whether Player 2's previous move was a hit or miss, as well as Player 1's new fire coordinate.
### 9. Player 2 Shoots Fourth
**Switch** `program.json`'s keys to Player 2. Player 2 makes their next move:
**Run**
```bash
leo run play '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 2048u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 2u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
}' 4u64
```
**Outputs**
```bash
➡️ Outputs
• {
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 2052u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 1145182747531998766752104305052328886102707397061849372000385383229513301534group.public
}
• {
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 4u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 2u64.private,
_nonce: 5958326936461495382488152485080596366937963499216527548334225566230682598418group.public
}
✅ Executed 'battleship.aleo/play'
```
### 10. Who Wins?
Play continues back and forth between Player 1 and Player 2.
When one player has a total of 14 flipped bits in their `hits_and_misses` field on their board_state.record,
they have won the game.
</details>
## ZK Battleship Privacy
How can we ensure that the ship configurations of each player remains secret,
while being able to trustlessly and fairly play with their opponent?
By taking advantage of selective privacy powered by zero knowledge proofs on Aleo.
Broadly speaking, we can follow this general strategy:
1. Create mathematical rules for placing the ships on the board, to ensure that neither player can cheat by stacking all their ships in one place, moving them off the board, or laying them across each other.
2. Ensure that the players and boards that begin a game cannot be swapped out.
3. Ensure that each player can only move once before the next player can move.
4. Enforce constraints on valid moves, and force the player to give their opponent information about their opponent's previous move in order to continue playing.
## Modeling the board and ships
Most battleship representations in programs use a 64 character string or an array of arrays (8 arrays of 8 elements each) to model the board state. Unfortunately, Aleo instructions don't represent strings well yet, nor can we use for or while loops. Luckily for us, Aleo has the unsigned 64 bit integer type, or u64. To represent every space on a battleship board, from top left to bottom right, we can use each bit in a u64. For example, an empty board would be:
0u64 =
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
```
Battleship is played with 4 different ship types -- a ship of length 5, length 4, length 3, and length 2. Some versions of battleship have an extra length 3 ship or another extra ship type, however, we will stick to the most basic version for this project. In order to be a valid ship placement, a ship must be placed vertically or horizontally (no diagonals). On a physical board, a ship cannot break across rows or intersect with another ship, but ships are allowed to touch one another.
Similar to how we represent a board with a u64 bitstring, we can represent a ship horizontally as a bitstring. We "flip" the bits to represent a ship:
| Length | Bitstring | u64 |
| ------ | --------- | --- |
| 5 | 11111 | 31u64|
| 4 | 1111 | 15u64|
| 3 | 111 | 7u64 |
| 2 | 11 | 3u64 |
We can also represent a ship vertically as a bitstring. To show this, we need 7 "unflipped" bits (zeroes) in between the flipped bits so that the bits are adjacent vertically.
| Length | Bitstring | u64 |
| --- | --- | --- |
| 5 | 1 00000001 00000001 00000001 00000001 | 4311810305u64 |
| 4 | 1 00000001 00000001 00000001 | 16843009u64 |
| 3 | 1 00000001 00000001 | 65793u64 |
| 2 | 1 00000001 | 257u64 |
With a board model and ship bitstring models, we can now place ships on a board.
<details><summary>Examples of valid board configurations:</summary>
17870284429256033024u64
```
1 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
1 1 1 1 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0
```
16383u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1
1 1 1 1 1 1 1 1
```
2157505700798988545u64
```
0 0 0 1 1 1 0 1
1 1 1 1 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
```
</details>
<details><summary>Examples of invalid board configurations:</summary>
Ships overlapping the bottom ship:
67503903u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 1 1 0
0 0 0 0 0 1 1 1
0 0 0 1 1 1 1 1
```
Diagonal ships:
9242549787790754436u64
```
1 0 0 0 0 0 0 0
0 1 0 0 0 1 0 0
0 0 1 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0
0 0 1 0 0 0 0 1
0 1 0 0 0 0 1 0
1 0 0 0 0 1 0 0
```
Ships splitting across rows and columns:
1297811850814034450u64
```
0 0 0 1 0 0 1 0
0 0 0 0 0 0 1 0
1 1 0 0 0 0 0 1
0 0 0 0 0 0 0 0
1 0 0 1 0 0 0 1
0 0 0 1 0 0 0 0
0 0 0 1 0 0 1 0
0 0 0 1 0 0 1 0
```
</details>
Given these rules, our strategy will be to validate each individaul ship bitstring placement on a board, and then, if all the ships are valid, compose all the positions onto a board and validate that the board with all ships are valid. If each individual ship's position is valid, then all the ships together should be valid unless any overlapping occurs.
## Validating a single ship at a time
To follow along with the code, all verification of ship bitstrings is done in verify.aleo. We know a ship is valid if all these conditions are met:
If horizontal:
1. The correct number of bits is flipped (a ship of length 5 should not have 6 flipped bits)
2. All the bits are adjacent to each other.
3. The bits do not split a row.
If vertical:
1. The correct number of bits is flipped.
2. All the bits are adjacent to each other, vertically. This means that each flipped bit should be separated by exactly 7 unflipped bits.
3. The bits do not split a column.
If a ship is valid vertically or horizontally, then we know the ship is valid. We just need to check for the bit count, the adjacency of those bits, and make sure those bits do not split a row/column. However, we can't loop through the bit string to count bits, or to make sure those bits don't break across columns. We'll need to turn to special bitwise operations and hacks.
<details><summary>Bit Counting</summary>
See the "c_bitcount" closure to follow along with the code. 50 years ago, MIT AI Laboratory published HAKMEM, which was a series of tricks and hacks to speed up processing for bitwise operations. https://w3.pppl.gov/~hammett/work/2009/AIM-239-ocr.pdf We turned to HAKMEM 169 for bitcounting inspiration, although we've tweaked our implementation to be (hopefully) easier to understand. Before diving into details, let's build some intuition.
Let a,b,c,d be either 0 or 1. Given a polynomial 8a + 4b + 2c + d, how do we find the summation of a + b + c + d?
If we subtract subsets of this polynomial, we'll be left with the summation.
Step 1: 8a + 4b + 2c + d
Step 2: -4a - 2b - c
Step 3: -2a - b
Step 4: - a
Step 5: = a + b + c + d
This polynomial is basically a bitwise representation of a number, so given a 4 bit number, e.g. 1011 or 13u64, we can follow these instructions to get the bit count. Step 2 is just subtracting the starting number but bit shifted to the right (equivalent to dividing by 2). Step 3 bit shifts the starting number to the right twice and is subtracted, and Step 4 bit shifts thrice and is subtracted. Put another way: Start with a 4-digit binary number A. A - (A >> 1) - (A >> 2) - (A >> 3) = B.
Step 1: 1101 = 13u64
Step 2: -0110 = 6u64
Step 3: -0011 = 3u64
Step 4: -0001 = 1u64
Step 5: =0011 = 3u64
To make this process work for any bit-length number, where the sum of the bits is left in groups of 4 bits, we'll need to use some bit-masking, so that the sum of one group of 4 does not interfere with the next group of 4.
With a larger starting number, like 1111 0001 0111 0110, we will need the following bit maskings:
```
For A >> 1, we'll use 0111 0111 0111 .... (in u64, this is 8608480567731124087u64)
For A >> 2, we'll use 0011 0011 0011 .... (in u64, this is 3689348814741910323u64)
For A >> 3, we'll use 0001 0001 0001 .... (in u64, this is 1229782938247303441u64)
```
For example, finding the sums of groups of 4 with a 16-bit number we'll call A to yield the bit sum number B:
```
A: 1111 0001 0111 0110
A>>1: 0111 1000 1011 1011
A>>2: 0011 1100 0101 1101
A>>3: 0001 1110 0010 1110
A>>1: 0111 1000 1011 1011
& 0111 0111 0111 0111:
0111 0000 0011 0011
A>>2: 0011 1100 0101 1101
& 0011 0011 0011 0011:
0011 0000 0001 0001
A>>3: 0001 1110 0010 1110
& 0001 0001 0001 0001:
0001 0000 0000 0000
A - (A>>1 & 0111....) - (A>>2 & 0011....) - (A>>3 & 0001....):
B: 0100 0001 0011 0010
4 1 3 2
```
The next step is to combine the summation of each of those 4-bit groups into sums of 8-bit groups. To do this, we'll use another bit trick. We will shift this number B to the right by 4 (B >> 4), and add that back to B. Then, we'll apply a bit masking of 0000 1111 0000 1111 .... (in u64, this is 1085102592571150095u64) to yield the sums of bits in groups of 8, a number we'll call C.
```
B: 0100 0001 0011 0010
B>>4: 0000 0100 0001 0011
0100 0101 0100 0101
4 5 4 5
apply the bit mask
0000 1111 0000 1111
C: 0000 0101 0000 0101
0 5 0 5
```
At this point, we've gone from a bit sum in groups of 4 to bit sums in groups of 8. That's great, but ultimately we want the total sum of bits in the original binary number. The final bit trick is to modulo C by 255. This is 2^8 - 1. For a bit of intuition, consider the number 1 0000 0001. If we take 1 0000 0001 mod 256, we're left with 1. If we take 1 0000 0001 mod 255, we're left with 2. Modding by 255 gives us the amount of bits _beyond_ the first 255 numbers, as 255 is the largest number that can be represented with 8 bits.
A full summary of abbreviated steps to get the bit count, starting with a 64 bit integer A (closely following the c_bitcount closure in the verify.aleo code):
let A = 64 unsigned bit integer
let B = A - (A>>1 & 8608480567731124087u64) - (A>>2 & 3689348814741910323u64) - (A>>3 & 1229782938247303441u64)
let C = (B - B>>4) & 1085102592571150095u64
bit count = C mod 255u64
</details>
<details><summary>Adjacency Check</summary>
Given a ship's placement on the board and its bitstring representation (horizontally or vertically), we can determine if the bits are adjacent. Follow the c_adjacency_check closure in verify.aleo. Given the ship of length 2, we know it's horizontal bitstring is 11 (3u64) and it's vertical bitstring is 100000001 (257u64). If on the board, the ship starts at the bottom right corner, its horizontal ship placement string would be:
3u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
```
Vertical ship placement:
257u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
```
If we move the ship to the left one column:
Horizontal 6u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0
```
Vertical 514u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0
```
If we move the ship up one row:
Horizontal 768u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0
```
Vertical 65792u64
```
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
```
We can make the observation that the original bitstring is always shifted by a power of 2 to get to a new valid position on the board. Therefore, if we take the ship placement bitstring and divide by the ship bitstring (either horizontal or vertical), as long as the remaining number is a power of 2 (2^0, 2^1, 2^2, 2^3...), we know the ship's bits are adjacent.
To ensure that the remaining number is a power of 2, we can use a bit trick. See the bit trick for ensuring a bitstring is a power of 2 section.
In the code, you'll notice one extra step. Dividing a ship placement bitstring by a ship bitstring representation could result in 0, and then subtracting by 1 will result in an underflow. In that case, we know the ship placement is not valid, so we can set a number which is gauranteed to not be a power of 2.
</details>
<details><summary>Splitting a row or column</summary>
Follow the c_horizontal_check closure in verify.aleo to follow the code. Assume all the bits are adjacent (see the adjacency check section). The column case is trivial. We can be certain that if a ship bitstring splits columns, the division of that ship placement bitstring by its ship bitstring representation will not yield a power of 2, and it would have failed the adjacency check.
The horizontal case must be checked because a split row bitstring could still contain a ship with adjacent bits. To make this check easier, we will condense the 64 bitstring into an 8 bitstring by taking it modulo 255. If we assume that a bitstring is not splitting a row, then taking the ship placement bitstring modulo 255 will yield an 8 bit valid bitstring. If the original ship placement bitstring is not valid, then we will have an invalid 8 bit bitstring. E.g.:
```
1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
```
mod 255 = 11100000 (valid)
```
0 0 0 0 0 0 0 1
1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
```
mod 255 = 11000001 (invalid)
How do we know the 8 bit bitstring is valid or not? We can simply do an adjacency check, as before.
</details>
<details><summary>Ensuring a bitstring is a power of 2</summary>
Any power of 2 will have a single bit flipped. If we subtract 1 from that number, it will result in a complementary bitstring that, bitwise-anded with the original, will always result in 0.
E.g.
```
8: 1000
8-1: 0111
8&7: 0000 == 0
7: 0111
7-1: 0110
7&6: 0110 != 0
```
</details>
## Validating all ships together in a single board
Give individual valid ship position bitstrings, we can combine all these together into a single board using bitwise or operators. See the create_board function in verify.aleo to follow the code. Once all ships are on the board, we can count the total number of bits, which should be 14 exactly for a ship of length 5, 4, 3, and 2.
## Ensure that players and boards cannot swap mid-game
Board states are represented with the board_state record. Each board has a flag indicating whether a game has been started with the board. This flag is set when offering a battleship game to an opponent, or accepting a battleship game from an opponent. Move records are created only in 3 ways:
1. Offering a battleship game creates a dummy move record that sets the two players to the addresses set in the board state record.
2. Accepting a battleship game consumes the first dummy move record and checks that the move record contains the same two players as the board of the player accepting the game. Then, a new dummy move record is created and keeps the same two players.
2. A move record must be consumed in order to play and create the next move record. There's a check to ensure the players in the move record matches the players in the board, and the players in the next move record are automatically set.
The only way moves _not_ matching a board can be combined is if the players begin multiple games with each other. As long as one player is honest and only accepts a single game with a particular opponent, only one set of moves can be played on one board between them.
## Ensure that each player can only move once before the next player can move
A move record must be consumed in order to create the next move record. The owner of the move record changes with each play. Player A must spend a move record in order to create a move record containing their fire coordinate, and that move record will be owned by Player B. Player B must spend that move record in order to create the next move record, which will belong to Player A.
## Enforce constraints on valid moves, and force the player to give their opponent information about their opponent's previous move in order to continue playing
A valid move for a player is a fire coordinate that has only one flipped bit in a u64. We can make sure only one bit is flipped with the powers of 2 bit trick. That single bit must be a coordinate that has not been played by that player before, which we check in board.aleo/update_played_tiles.
In order to give their next move to their opponent, a player must call the main.aleo/play function, which checks the opponent's fire coordinate on the current player's board. The move record being created is updated with whether that fire coordinate was a hit or a miss for the opponent.
## Winning the game
Right now, the way to check when a game has been won is to count the number of hits on your hits_and_misses field on your board_state record. Once you have 14 hits, you've won the game.

View File

@ -0,0 +1,117 @@
// Battleship boards are represented by 8x8 squares.
// A u64 is all that is required to represent a hit or a miss on a single board.
// Starting from the top row, left to right, a hit is 1 and a miss is 0.
// A first move resulting in a hit in row 1, column 3 would be:
// 00100000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
// A second u64 is needed to represent which squares have been played, with 1s being played squares and 0s being
// unplayed squares.
record board_state {
owner: address,
gates: u64,
// The hits and misses registered on the opponent's board.
hits_and_misses: u64,
// The squares that have been played on the opponent's board.
played_tiles: u64,
// The ship bitstring representing all ship positions on your own board
ships: u64,
player_1: address,
player_2: address,
game_started: bool,
}
// Returns a new board_state.
@program
function new_board_state(
ships: u64,
opponent: address,
) -> board_state {
return board_state {
owner: self.caller,
gates: 0u64,
hits_and_misses: 0u64,
played_tiles: 0u64,
ships,
player_1: self.caller,
player_2: opponent,
game_started: false,
};
}
// Returns a new board state that has been started.
// Fails if this board has been started before.
@program
function start_board(
// The record of the board to start. A board can only be started once.
board: board_state,
) -> board_state {
// Ensure this board hasn't been used to start a game before.
console.assert(!board.game_started);
return board_state {
owner: board.owner,
gates: board.gates,
hits_and_misses: board.hits_and_misses,
played_tiles: board.played_tiles,
ships: board.ships,
player_1: board.player_1,
player_2: board.player_2,
game_started: true,
};
}
// Returns a new board state record that includes all the played tiles.
// Fails if r1 has been played before.
@program
function update_played_tiles(
// The record of the board to update.
board: board_state,
// The u64 equivalent of a bitstring fire coordinate to send to the opponent.
shoot: u64,
) -> board_state {
// Need to make sure r1 is a valid move. Only one bit of r1 should be flipped.
let flip_bit: u64 = shoot - 1u64;
// bitwise and operation
let check_move: u64 = shoot & flip_bit;
console.assert_eq(check_move, 0u64);
// Need to make sure r1 is a valid move given the played_tiles. no bits should overlap.
let check_tiles: u64 = shoot & board.played_tiles;
console.assert_eq(check_tiles, 0u64);
// Update played tiles.
let played_tiles: u64 = board.played_tiles | shoot;
return board_state {
owner: board.owner,
gates: board.gates,
hits_and_misses: board.hits_and_misses,
played_tiles,
ships: board.ships,
player_1: board.player_1,
player_2: board.player_2,
game_started: board.game_started,
};
}
// Returns a new board state record that includes all the hits and misses.
@program
function update_hits_and_misses(
// The record of the board to update.
board: board_state,
// The u64 equivalent of a bitstring of whether this player's previous move was a hit or miss.
hit_or_miss: u64,
) -> board_state {
// Update hits and misses.
let hits_and_misses: u64 = board.hits_and_misses | hit_or_miss;
return board_state {
owner: board.owner,
gates: board.gates,
hits_and_misses,
played_tiles: board.played_tiles,
ships: board.ships,
player_1: board.player_1,
player_2: board.player_2,
game_started: board.game_started,
};
}

View File

@ -0,0 +1,48 @@
record move {
owner: address,
gates: u64,
incoming_fire_coordinate: u64,
player_1: address,
player_2: address,
// One flipped bit indicates a hit. No flipped bits indicates a miss.
prev_hit_or_miss: u64,
}
// Returns new move record owned by the opponent.
@program
function create_move(
// The move record created by the opponent.
move_record: move,
// The u64 representation of incoming_fire_coordinate, the bitstring fire coordinate to send to the opponent.
incoming_fire_coordinate: u64,
// The u64 representation of prev_hit_or_miss, this player's previous fire coordinate as a hit or miss.
prev_hit_or_miss: u64,
) -> move {
// A new move record should be created and owned by the opponent.
let one_is_owner: bool = move_record.player_1 == move_record.owner;
let opponent: address = one_is_owner ? move_record.player_2 : move_record.player_1;
return move {
owner: opponent,
gates: move_record.gates,
incoming_fire_coordinate,
player_1: move_record.player_2,
player_2: move_record.player_1,
prev_hit_or_miss,
};
}
// Returns the move record owned by the opponent.
// Note, this move record contains dummy fire coordinates and previous hit or miss.
@program
function start_game(player_2: address) -> move {
return move {
owner: player_2,
gates: 0u64,
incoming_fire_coordinate: 0u64,
player_1: self.caller,
player_2: player_2,
prev_hit_or_miss: 0u64,
};
}

View File

@ -0,0 +1,125 @@
// Returns the number of flipped bits.
// E.g. 17870283321406128128u64, in binary 11111000 00000000 00000000 00000000 00000000 00000000 00000000 00000000,
// returns 5u64;
function bitcount(bits: u64) -> u64 {
let r1: u64 = bits / 2u64;
let r2: u64 = bits / 4u64;
let r3: u64 = bits / 8u64;
let r4: u64 = r1 & 8608480567731124087u64;
let r5: u64 = r2 & 3689348814741910323u64;
let r6: u64 = r3 & 1229782938247303441u64;
let r7: u64 = bits - r4 - r5 - r6;
let r8: u64 = r7 / 16u64;
let r9: u64 = r7 + r8;
let r10: u64 = r9 & 1085102592571150095u64;
let r11: u64 = r10 % 255u64;
return r11;
}
// Returns boolean of whether all the flipped bits in location are "adjacent". Horizontally, this means all flipped bits are
// directly next to each other (111). Vertically, this means all flipped bits are separated by 7 unflipped bits
// (10000000100000001).
function adjacency_check(
// The u64 representation of a ship's placement in an 8x8 grid.
ship: u64,
// The u64 representation of a ship's bitstring, either horizontally or vertically.
// E.g. a ship of length 3's bit string horizontally would be: 000111 = 7u64. Vertically, the bit string would be:
// 10000000100000001 = 65793u64.
orientation: u64,
) -> bool {
// This may result in 0.
let division: u64 = ship / orientation;
// subtracting 1 from 0 will cause an underflow, so we should check for this edge case.
let is_eq: bool = division == 0u64;
// if the above division resulted in 0, we know the adjacency check should return false.
// Setting to r4 to 3 (11) will guarantee failure here.
let ternary: u64 = is_eq ? 3u64 : division;
let subtraction: u64 = ternary - 1u64;
let and: u64 = subtraction & ternary;
let bits_are_adjacent: bool = and == 0u64;
return bits_are_adjacent;
}
// Returns boolean of whether adjacent flipped bits don't split a row of size 8.
// E.g. 111000000 has adjacent flipped bits but splits a row: 00000001 11000000
function horizontal_check(
// The u64 representation of a ship's placement in an 8x8 grid.
ship: u64,
// The u64 representation of a ship's bitstring horizontally.
horizontal: u64,
) -> bool {
let remainder: u64 = ship % 255u64;
// This may result in 0.
let division: u64 = remainder / horizontal;
// Subtracting 1 from 0 will cause an underflow.
let is_eq: bool = division == 0u64;
// Setting to 3 will guarantee failure.
let ternary: u64 = is_eq ? 3u64 : division;
let subtraction: u64 = ternary - 1u64;
let and: u64 = subtraction & ternary;
let bits_split_row: bool = and == 0u64;
return bits_split_row;
}
// Returns `true` if the ship placement is valid.
@program
function validate_ship(
// The u64 representation of a ship's placement in an 8x8 grid.
ship: u64,
// The length of the placed ship.
length: u64,
// The u64 equivalent of a ship's horizontal bitstring representation.
horizontal: u64,
// The u64 equivalent of a ship's vertical bitstring representation.
vertical: u64,
) -> bool {
// Check bitcount -- all other validations depend on the bitcount being correct.
let num_bits: u64 = bitcount(ship);
console.assert_eq(num_bits, length);
// Check horizontal bits of ship.
let is_adjacent: bool = adjacency_check(ship, horizontal); // True if bits are adjacent horizontally.
let is_horizontal: bool = horizontal_check(ship, horizontal); // True if those horizontal bits are not split across rows.
let valid_horizontal: bool = is_adjacent && is_horizontal; // True if bits are adjacent horizontally and not split across rows.
// Check vertical bits of ship.
let valid_vertical: bool = adjacency_check(ship, vertical); // True if bits are adjacent vertically.
let ship_is_valid: bool = valid_horizontal || valid_vertical; // Ship is valid if it is vertically or horizontally valid.
return ship_is_valid;
}
// Returns the u64 representation of all the ships' placements in an 8x8 grid. This function will fail
// if any of the ship placements overlap each other.
@program
function create_board(
// The u64 representation of a carrier's placement in an 8x8 grid. Length = 5.
carrier: u64,
// The u64 representation of a battleship's placement in an 8x8 grid. Length = 4.
battleship: u64,
// The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3.
cruiser: u64,
// The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2.
destroyer: u64,
) -> u64 {
// Bitwise combine the ship placements together
let ships: u64 = carrier | battleship | cruiser | destroyer;
let num_bits: u64 = bitcount(ships);
console.assert_eq(num_bits, 14u64); // Given 4 individually-valid ships, a valid combination should yield exactly 14 flipped bits.
return ships;
}

View File

@ -0,0 +1,4 @@
// The program input for battleship/src/main.leo
[main]
public a: u32 = 1u32;
b: u32 = 2u32;

View File

@ -0,0 +1,11 @@
{
"program": "battleship.aleo",
"version": "0.0.0",
"description": "Play ZK Battleship",
"development": {
"private_key": "APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm",
"view_key": "AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6",
"address": "aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy"
},
"license": "MIT"
}

216
examples/battleship/run.sh Executable file
View File

@ -0,0 +1,216 @@
#!/bin/bash
# First check that Leo is installed.
if ! command -v leo &> /dev/null
then
echo "leo is not installed."
exit
fi
# Follow along in the README.md for a detailed explanation of each step.
# 1. Setup
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm\",
\"view_key\": \"AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6\",
\"address\": \"aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy\"
},
\"license\": \"MIT\"
}" > program.json
# 2. Select Player 1's Board
leo run initialize_board 34084860461056u64 551911718912u64 7u64 1157425104234217472u64 aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry
# 3. Pass to Player 2
leo run offer_battleship '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: false.private,
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
}'
# 4. Select Player 2's Board
(
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkp86FNGdKxjgAdgQZ967bqBanjuHkAaoRe19RK24ZCGsHH\",
\"view_key\": \"AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE\",
\"address\": \"aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry\"
},
\"license\": \"MIT\"
}" > program.json
leo run initialize_board 31u64 2207646875648u64 224u64 9042383626829824u64 aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy
)
# 5. Pass to Player 1
leo run start_battleship '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: false.private,
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
}'
# 6. Player 1 Shoots First
(
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm\",
\"view_key\": \"AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6\",
\"address\": \"aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy\"
},
\"license\": \"MIT\"
}" > program.json
leo run play '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
}' '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 0u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 0u64.private,
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
}' 1u64
)
# 7. Player 2 Shoots Second
(
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkp86FNGdKxjgAdgQZ967bqBanjuHkAaoRe19RK24ZCGsHH\",
\"view_key\": \"AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE\",
\"address\": \"aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry\"
},
\"license\": \"MIT\"
}" > program.json
leo run play '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 0u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 1u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
}' 2048u64
)
# 8. Player 1 Shoots Third
(
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkpGKaJY47BXb6knSqmT3JZnBUEGBDFAWz2nMVSsjwYpJmm\",
\"view_key\": \"AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6\",
\"address\": \"aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy\"
},
\"license\": \"MIT\"
}" > program.json
leo run play '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 1u64.private,
ships: 1157459741006397447u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
game_started: true.private,
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
}' '{
owner: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
gates: 0u64.private,
incoming_fire_coordinate: 2048u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
prev_hit_or_miss: 1u64.private,
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
}' 2u64
)
# 9. Player 2 Shoots Fourth
(
echo "{
\"program\": \"battleship.aleo\",
\"version\": \"0.0.0\",
\"description\": \"\",
\"development\": {
\"private_key\": \"APrivateKey1zkp86FNGdKxjgAdgQZ967bqBanjuHkAaoRe19RK24ZCGsHH\",
\"view_key\": \"AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE\",
\"address\": \"aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry\"
},
\"license\": \"MIT\"
}" > program.json
leo run play '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
hits_and_misses: 0u64.private,
played_tiles: 2048u64.private,
ships: 9044591273705727u64.private,
player_1: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
player_2: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
game_started: true.private,
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
}' '{
owner: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
gates: 0u64.private,
incoming_fire_coordinate: 2u64.private,
player_1: aleo15g9c69urtdhvfml0vjl8px07txmxsy454urhgzk57szmcuttpqgq5cvcdy.private,
player_2: aleo1wyvu96dvv0auq9e4qme54kjuhzglyfcf576h0g3nrrmrmr0505pqd6wnry.private,
prev_hit_or_miss: 0u64.private,
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
}' 4u64
)

View File

@ -0,0 +1,106 @@
// The 'battleship.leo' program.
import board.leo;
import move.leo;
import verify.leo;
// Returns a new record representing a new game of battleship.
@program
function initialize_board(
// The u64 representation of a carrier's placement in an 8x8 grid. Length = 5.
carrier: u64,
// The u64 representation of a battleship's placement in an 8x8 grid. Length = 4.
battleship: u64,
// The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3.
cruiser: u64,
// The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2.
destroyer: u64,
// The address of the opponent.
player: address,
) -> 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);
let valid_battleship: bool = verify.leo/validate_ship(battleship, 4u64, 15u64, 16843009u64);
console.assert(valid_battleship);
let valid_cruiser: bool = verify.leo/validate_ship(cruiser, 3u64, 7u64, 65793u64);
console.assert(valid_cruiser);
let valid_destroyer: bool = verify.leo/validate_ship(destroyer, 2u64, 3u64, 257u64);
console.assert(valid_destroyer);
// Create the board with all the ship placements combined.
let board: u64 = verify.leo/create_board(carrier, battleship, cruiser, destroyer);
// Initialize the board state record.
let state: board_state = board.leo/new_board_state(board, player);
return state;
}
// Returns an updated board state record that has been started. This board cannot be used to start any other games.
// Returns a dummy move record owned by the opponent.
// This function commits a given board to a game with an opponent and creates the initial dummy move.
@program
function offer_battleship(
// The board record to start a game with.
board: board.leo/board_state.record,
) -> (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);
return (state, dummy);
}
// Returns updated board_state.record that has been started and can no longer be used to join or start new games.
// Returns dummy move record owned by the opponent.
@program
function start_battleship(
// The board record to play the game with.
board: board.leo/board_state.record,
// The move record to play to begin the game. This should be the dummy move record created from offer_battleship.
move_start: move.leo/move.record,
) -> (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_2);
console.assert_eq(board.player_2, move_start.player_1);
let state: board_state = board.leo/start_board(board);
let dummy: move = move.leo/start_game(board.player_2);
return (state, dummy);
}
// Returns updated board record.
// Returns new move record owned by opponent.
@program
function play(
// The board record to update.
board: board.leo/board_state.record,
// The incoming move from the opponent.
move_incoming: move.leo/move.record,
// The u64 equivalent of the bitwise representation of the next coordinate to play on the opponent's board.
shoot: u64,
) -> (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);
// Validate that the move players and board players match each other.
console.assert_eq(board.player_1, move_incoming.player_2);
console.assert_eq(board.player_2, move_incoming.player_1);
// Play coordinate on own board. Will fail if not a valid move.
let hit_or_miss: board_state = board.leo/update_played_tiles(board, shoot);
// Update own board with result of last shot.
let next_board: board_state = board.leo/update_hits_and_misses(hit_or_miss, move_incoming.prev_hit_or_miss);
// Assess whether incoming fire coordinate is a hit.
let is_hit: u64 = move_incoming.incoming_fire_coordinate & board.ships;
let next_move: move = move.leo/create_move(move_incoming, shoot, is_hit);
return (next_board, next_move);
}

View File

View File

@ -27,7 +27,6 @@ use leo_span::symbol::with_session_globals;
use aleo::commands::Build as AleoBuild;
use clap::StructOpt;
use colored::Colorize;
use indexmap::IndexMap;
use std::io::Write;
use std::path::{Path, PathBuf};
@ -275,14 +274,10 @@ fn compile_leo_file(
.map_err(CliError::failed_to_load_instructions)?;
// Prepare the path string.
let path_string = format!("(in \"{}\")", aleo_file_path.display());
let _path_string = format!("(in \"{}\")", aleo_file_path.display());
// Log the build as successful.
tracing::info!(
"compiled '{}' into Aleo instructions {}",
file_name,
path_string.dimmed()
);
tracing::info!("Compiled '{}' into Aleo instructions", file_name,);
Ok(symbol_table.circuits)
}

View File

@ -50,6 +50,7 @@ impl Command for Deploy {
.map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?;
// Call the `aleo node` command from the Aleo SDK.
println!();
let command = AleoDeploy::try_parse_from([ALEO_CLI_COMMAND]).map_err(CliError::failed_to_parse_aleo_node)?;
let res = command.parse().map_err(CliError::failed_to_execute_aleo_node)?;

View File

@ -71,6 +71,7 @@ impl Command for Node {
}
// Call the `aleo node` command from the Aleo SDK.
println!();
let command = AleoNode::try_parse_from(&arguments).map_err(CliError::failed_to_parse_aleo_node)?;
let res = command.parse().map_err(CliError::failed_to_execute_aleo_node)?;

View File

@ -86,6 +86,7 @@ impl Command for Run {
if self.compiler_options.offline {
arguments.push(String::from("--offline"));
}
println!();
let command = AleoRun::try_parse_from(&arguments).map_err(CliError::failed_to_parse_aleo_run)?;
let res = command.parse().map_err(CliError::failed_to_execute_aleo_run)?;

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: ef995e1b03c6e17ab0a2f908f4cd7957ea281fdc38834cbaed1dac75086b6eef
initial_ast: 74111c6007aa40eb2a994d3714e0957f54863e3f28e84a1d65026d8a6ba96c45
unrolled_ast: 74111c6007aa40eb2a994d3714e0957f54863e3f28e84a1d65026d8a6ba96c45
ssa_ast: 19e71c476a02d508dd74b3a480961e509811a0159aa91c6f22d054c84ef821f0
flattened_ast: 730b7aeb357218b32fecb9e2e1eb38fa2f3231071102956b1a11565ec994c91b
initial_ast: 60aca426daf9ba37188e78c4038830dc721f2544b371287c706eae9c679369e2
unrolled_ast: 60aca426daf9ba37188e78c4038830dc721f2544b371287c706eae9c679369e2
ssa_ast: ffb0fe310fd41b870adaadb055a6866d90a28b2d15675dc8b8b7a05d103b9ef3
flattened_ast: 00ea8a92ad75e87178b948dd45de6e701d58f9d68a3129f9c9ed85610a35f41a

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8a386677fc570d7f57e8e5259334608ddef2d04d55e1aea9aa591c1d95bc84b7
initial_ast: 9148ad7f9de7c5bad3ad096ef2c9156d11364229232531510ce6dfd05fed1839
unrolled_ast: 9148ad7f9de7c5bad3ad096ef2c9156d11364229232531510ce6dfd05fed1839
ssa_ast: 9c561ee9a8e1d2411f61c20a950d7cb666f214504ccfb57f12df9bda217118dd
flattened_ast: 6d9d96e670166c6bcf22c0a415e9b31c4e6a4728588a1328db931943af24de92
initial_ast: 2057e381209aacbb5f7679c3748c5669fe8e5c6e3c2dc0884445129b310dd8de
unrolled_ast: 2057e381209aacbb5f7679c3748c5669fe8e5c6e3c2dc0884445129b310dd8de
ssa_ast: 74bf56b2e3cb0f39e34e429e00035546354f63e514506a71b0dc09a0ce10e822
flattened_ast: 21ba244f2fca28ee8139d9c7c93d905e9165baeaa0c4d19c909e9ca1dc5b168e

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 7223f540c91cd639cc122936a41fc896f821e2d57c9f6f086eb4d555dc9c9217
initial_ast: 984b0062c1c2710920f61c2c01254ecd451e88594c8ddec6ab3fe60a3b6bf40e
unrolled_ast: 984b0062c1c2710920f61c2c01254ecd451e88594c8ddec6ab3fe60a3b6bf40e
ssa_ast: 6ec9e9f3f2b308055a8bc7fb6467270504f5cea4371bf8e897a250966e48b1e9
flattened_ast: be2fde3a85189d931c76091d31a7eda0b147745a58ea5e90bbd3516758159857
initial_ast: 7f6c228ca30ad15e4d2fb0d8c1030c0c89cffe4cd592d9a9b85e2f9658cf5dab
unrolled_ast: 7f6c228ca30ad15e4d2fb0d8c1030c0c89cffe4cd592d9a9b85e2f9658cf5dab
ssa_ast: dad403b3b1c2d302c8e06b15afe87117a3809e17fb20c17d95348850c2bd6090
flattened_ast: a014cbddcd80de26e1a5fa463ee253af4e9a6ced76b9f225534587e7fae2f322

View File

@ -5,7 +5,7 @@ outputs:
- output:
- initial_input_ast: 5cb9782988c5736339747224b8ed4a38ee869231d131a55515cfa1f98de065cc
- initial_input_ast: 079946da42e7c73ef17f4385e8ca310259a5e0f1e6471abee30b6175f413e480
initial_ast: 147420ccb81a27cec8f8317bca208aef21b46219dc75e1f967fbc3482c30ea30
unrolled_ast: 147420ccb81a27cec8f8317bca208aef21b46219dc75e1f967fbc3482c30ea30
ssa_ast: 80979f0c0496857d1931e5f4d36bfa7e65e71ea4d95d8baba06b4203d9a2f6c1
flattened_ast: dd38d7d95e4c974fe18b78ca7c4127ed327b0877a5847b47fa3e954a14e94fb5
initial_ast: 16d9d56e3e3ea77b9155cf64a6c79469f0115fa4afcd157289c3b5313a6bf380
unrolled_ast: 16d9d56e3e3ea77b9155cf64a6c79469f0115fa4afcd157289c3b5313a6bf380
ssa_ast: b15b8ea256e969644b29e1eddcef7f795c2ae4fa39d7b22f4bc0ef6b4544a9b0
flattened_ast: 69a909d1769d57390df47742afe613b795626f5f601ea410eae76945857d739c

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: f049b2866e2ec8e876ccaa3221109137b3d895d7ebfa0917506009861c15c687
- initial_input_ast: e047d07a8d39dbab50f3b02256ff7a58f9ba2a8b9128ef7f79867add3fd4416e
- initial_input_ast: 5dd6a99b2d55a543947f75934bbbc7f32ab8478a5b1a567e6c917aaa1800d4ec
initial_ast: c1068c7526ed38b32a16d2b7904f184af3e685fe909524d100448b4b74db20bc
unrolled_ast: c1068c7526ed38b32a16d2b7904f184af3e685fe909524d100448b4b74db20bc
ssa_ast: 1284bdb8af4f441f2ef8a017d30c80ef018c40ad2d3edfb62e8a44b8dde7456f
flattened_ast: 16b548d170575c2646dbf5585a66410f111577baf27f93c7e4621b791a63676a
initial_ast: 6c3577e8555c2e47b24e5599aea21b417ef4e1a09ba08391caa2335c9cbf5379
unrolled_ast: 6c3577e8555c2e47b24e5599aea21b417ef4e1a09ba08391caa2335c9cbf5379
ssa_ast: e6db1a1540fd341f651de401faeae13790ebf087667cee54a3e3a749baccaac0
flattened_ast: f53398d8adc2ae8703535963f4e99bf880642232b51e63dfce71b76efe808bcc

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: 7a6c45e7cac800efe7f8d73af2fb9e926f49c62073a5cb13c463670ca0234ff7
- initial_input_ast: 0ac5a86e326e8f5f561e1030162ee1a307bdf56425abe3cafe38b8bda4aad86b
- initial_input_ast: 9eebe7b8b91000400e94d9513f5be1c50c51207e0e5105248f68789e74aa82c5
initial_ast: b05ffaa1c5f53b6554d685557606710657817f5fe5a6de2b3dff4ce20426699f
unrolled_ast: b05ffaa1c5f53b6554d685557606710657817f5fe5a6de2b3dff4ce20426699f
ssa_ast: 5d166a4ff1741b1130c4d8818444473bcf7ee8fd915f13df0568ea7a238976dd
flattened_ast: 677d26faf130b3e947577ec07ce4221badb04867fc4fd07fec38fdf55dd52aa1
initial_ast: 1e0768370b05b457606c489f079b7d69d61f8364f606c003f3a27eb015fb2870
unrolled_ast: 1e0768370b05b457606c489f079b7d69d61f8364f606c003f3a27eb015fb2870
ssa_ast: bb8eb614f4922393c678cd290f53e76c3e7b5ca498e7a8eb066dc2b59c968c70
flattened_ast: 7762192411e8d269a91c099925df5d23fcd930a59aa8119bc0d0ef86c0e849c9

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: f049b2866e2ec8e876ccaa3221109137b3d895d7ebfa0917506009861c15c687
- initial_input_ast: e047d07a8d39dbab50f3b02256ff7a58f9ba2a8b9128ef7f79867add3fd4416e
- initial_input_ast: 5dd6a99b2d55a543947f75934bbbc7f32ab8478a5b1a567e6c917aaa1800d4ec
initial_ast: f399e79c79f74ef3da53a264324b275d6e820ae0942aa61305fadfd37e1cd482
unrolled_ast: f399e79c79f74ef3da53a264324b275d6e820ae0942aa61305fadfd37e1cd482
ssa_ast: 5d81d7d85c433c988b0577172cca792d0e4f5c3cac420f6eb624d012587e2d3d
flattened_ast: ffc0a94a0212e64c06dfc3e39fc346b11acf8e29a33135ea41214ce2e2b7bdfa
initial_ast: dcb75947a83d758e1129f8e9c8acac23445175fd9b713f455a64a075b9b22eb4
unrolled_ast: dcb75947a83d758e1129f8e9c8acac23445175fd9b713f455a64a075b9b22eb4
ssa_ast: bbd2a981628e8e7a572eb8bcabad77fa0d7db8c259c6783031a49ec6c60efb96
flattened_ast: a88d8bbfc4bb2b94700869c8646a04faf2ed1cc72685b952f4f5157235d5ad5e

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: f049b2866e2ec8e876ccaa3221109137b3d895d7ebfa0917506009861c15c687
- initial_input_ast: e047d07a8d39dbab50f3b02256ff7a58f9ba2a8b9128ef7f79867add3fd4416e
- initial_input_ast: 5dd6a99b2d55a543947f75934bbbc7f32ab8478a5b1a567e6c917aaa1800d4ec
initial_ast: e42cb810be0717104eae244acdc53f95ea37a739554ee0978a9b693bc93a92a3
unrolled_ast: e42cb810be0717104eae244acdc53f95ea37a739554ee0978a9b693bc93a92a3
ssa_ast: ffffd952b1e2cd9f35fa84b65d52c9177de1be81c9ac90204f7737166e805f65
flattened_ast: b10035dd45fabd6d2f76b84e1d6c7051658f968c2dbfdb4fadd5d11766989f64
initial_ast: d26dbb6f0ebeab08c4b96f40b97e9d3f90e4afbda410da2bf44046c7f8d4b739
unrolled_ast: d26dbb6f0ebeab08c4b96f40b97e9d3f90e4afbda410da2bf44046c7f8d4b739
ssa_ast: 935f510986a42c0fbabb1143a92e20d13b025f903278d2bdb59ebe69e4e0dee7
flattened_ast: f1bb513e7c53f0a62d3147b47bd6a93f0a67f2ad02fc93000229283071d61631

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: 6da90d928d023c26a92106b9ef3bbf3d6e1ee2fcf67b16aa9c8477477cb4b064
- initial_input_ast: d82ff0fb53ab27ed095ea5bbb4e118fbde50d4508caed65cb8029ad7441ef0fd
- initial_input_ast: 07a295a1403e9020a1fb03ddcaf92b18a3237d1d4ad70b1549db77f1e2d1e6b0
initial_ast: 79a70f233888d2d8040892c75993e0ee543cf2e0580bb48fb26d2ea434779433
unrolled_ast: 79a70f233888d2d8040892c75993e0ee543cf2e0580bb48fb26d2ea434779433
ssa_ast: e303fb7679c44ee8ca24597af136b2b5f2eabdc778cc9539c9029e58242a6292
flattened_ast: 81ceed9d1bfb8f7e8c7284d456286489cb198ff4f8270ef31d5b632afead1215
initial_ast: da9c528bc9e8e66ded4039a07f8126faa611d78f057eaea291be616ba83631b9
unrolled_ast: da9c528bc9e8e66ded4039a07f8126faa611d78f057eaea291be616ba83631b9
ssa_ast: 90b3e5210fb372c270b93c462a25be0b2ea44802136a6bf2e3179e05334893d5
flattened_ast: a2229e04ce6fd04fd20a08eab36d29da02ef24f8a3f2870c111ddb4ce0eda5c3

View File

@ -7,7 +7,7 @@ outputs:
- initial_input_ast: f049b2866e2ec8e876ccaa3221109137b3d895d7ebfa0917506009861c15c687
- initial_input_ast: e047d07a8d39dbab50f3b02256ff7a58f9ba2a8b9128ef7f79867add3fd4416e
- initial_input_ast: 5dd6a99b2d55a543947f75934bbbc7f32ab8478a5b1a567e6c917aaa1800d4ec
initial_ast: 881a81aea7b6779e5075e88bdff48739d34bb303ef2e037f4459aa96777eb30e
unrolled_ast: 881a81aea7b6779e5075e88bdff48739d34bb303ef2e037f4459aa96777eb30e
ssa_ast: 527aa0d4483de722a0e1b9d11336b402fa7944e003892a51d2ae3c74acc3248c
flattened_ast: 03a8cdde887d1c556a568d291dc8901b6eed765d507ee82727576edf05a6ce64
initial_ast: 542e4b787820da86029a2d091fbd1c4f550d5c79ebe00aa3a8d0c4791fe75bf2
unrolled_ast: 542e4b787820da86029a2d091fbd1c4f550d5c79ebe00aa3a8d0c4791fe75bf2
ssa_ast: d81976651a4f5467eddb86cad6139ea40cc30811544b929fd9cc232510921751
flattened_ast: 30d5332085a4dad240b2b59e3c005d839ae3d13ac5705d03aa7989e792c71f10

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: d6ea059c4a9c0394d538bbc34b56f762226d75fe3655475bfb6cab78c0479657
unrolled_ast: d6ea059c4a9c0394d538bbc34b56f762226d75fe3655475bfb6cab78c0479657
ssa_ast: 40b30a4ce233c28c60f9f7d05df0fdfeb6a6ca34000757a4f738cbbcad629c59
flattened_ast: 3a4845ad0923ff344ef60ce26dad1ac5d424f89c82977a5967baa0884385d942
initial_ast: 399e5c01eac6776b8f22bd1804d979cf56914f6d2e0c1e24c3296287daa4b030
unrolled_ast: 399e5c01eac6776b8f22bd1804d979cf56914f6d2e0c1e24c3296287daa4b030
ssa_ast: c303a8ad534e6172946c7b39bcb6f45fe28e9c9e33f018bae1b783698c992521
flattened_ast: dfeaca780c19e422dc1b54b111daf9ddf99338747dad148333eb49f64a54e659

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8fbdc7881fb5e917ccec6859b63f376841069ddada687114f1ff6f364e282e8c
initial_ast: 935321dac8ae215562c7bfd5a61e6f753d5ac28482ab3b4959e09606e3e139c3
unrolled_ast: 935321dac8ae215562c7bfd5a61e6f753d5ac28482ab3b4959e09606e3e139c3
ssa_ast: 6c6f83690c46e2633c54f370eabff03bc7a83f87d2c715dfc16ff8e9c9eb429e
flattened_ast: 07db7f71c5fe89b1adf16160a62a5b45916602121b3e6039c9fed19e0c74b5d4
initial_ast: 2682cb2889f0cb90c9cce25a9568b3c5ab110ca57e18a81e323b76cb7783436f
unrolled_ast: 2682cb2889f0cb90c9cce25a9568b3c5ab110ca57e18a81e323b76cb7783436f
ssa_ast: 4a197c73ea1b81a777c81f5d2b07097d931a760b39e32aa453af8187ac0c6340
flattened_ast: 85f663133486589eb5c754ecae07ae645b45df26216a39a19cbd62f1c9725eb5

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 00ae278f2e47685455a873498a580f06abfcb7bae93cc5844c2616a7da7d03db
initial_ast: a94e6ddf6a6d4711f93ee4796d74ade5525c060709fc5ec3174fc75b2f22da1a
unrolled_ast: a94e6ddf6a6d4711f93ee4796d74ade5525c060709fc5ec3174fc75b2f22da1a
ssa_ast: e0faa26023feac3c025773f0d48b6c199b01d477e490e3dae47ccaebffde5c28
flattened_ast: 3998a8b5bfbef98ab1b2702b5d826a56681f02d503cd78351ca72ba0bf6da113
initial_ast: ce017104a41591f5c5e5ed2893922df2cf28c22522729e8bbed5998090a72cd8
unrolled_ast: ce017104a41591f5c5e5ed2893922df2cf28c22522729e8bbed5998090a72cd8
ssa_ast: 5e31a762306b5928c8899e504c7430221c09f49b8490eab1e3171f84ea9a0c75
flattened_ast: 529d582e6b4910c70e30aec56190cad7b51ca512f216cf2784d420a0cae0841c

View File

@ -1,9 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 6f105b81caca7b2268ee9ac70dcb674b02e48d8a29b026aa94c2cb12c46789cc
initial_ast: b9f8e6b1ae0f57caff61df33ff2ed4b01a5fc0d63b8b2665fb5b1a51ad328c20
unrolled_ast: b9f8e6b1ae0f57caff61df33ff2ed4b01a5fc0d63b8b2665fb5b1a51ad328c20
ssa_ast: e74d211efe5f9307eb7468be5328e602d5a24570cd89e2baf2380d43b8e13781

View File

@ -1,9 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 8d27a137e4677982055885ce77e8982228972abc6ed4ca1638d04c3183d19e07
initial_ast: 0794be1b37a9427e23aa22110bbaa681591db003a82261c5e061627b67325093
unrolled_ast: 0794be1b37a9427e23aa22110bbaa681591db003a82261c5e061627b67325093
ssa_ast: cd94223532a0d279db96857167a3088db1c780a3eab2b8d1bc36c3252064f7cd

View File

@ -1,10 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 06ca750e19583956979968f4f3fa54ae1e11219af80c88b2722ca4a169b48751
- initial_input_ast: bdf478032fd867197166feec39cb6c567c15c78a9b0ce919730dc36ed5fdfac2
initial_ast: 3bb4a339efa4ee13910a9d124bfa9accfabb3f0ee2ea26bb0fc801bf3060f665
unrolled_ast: 3bb4a339efa4ee13910a9d124bfa9accfabb3f0ee2ea26bb0fc801bf3060f665
ssa_ast: b3d3761e28a85e547e9577d3e7daeb5e342561cdfb99d29b95e41a6ad5436fc1

View File

@ -1,5 +0,0 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [EPAR0370005]: expected -> -- found '{'\n --> compiler-test:3:17\n |\n 3 | function main() {\n | ^"

View File

@ -1,9 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: fea9fe8b6d89ea2018cac145aeebb2240a195f9cf3586ee60558e81791e9ebd0
initial_ast: c622fa0ba9993d1fd88da65aae2d2c6ec68f529a136dafc989a1da601e994a18
unrolled_ast: c622fa0ba9993d1fd88da65aae2d2c6ec68f529a136dafc989a1da601e994a18
ssa_ast: 5b0162059ae3278dd27cf6b715fe8924be7e53baf749b64b3ce03a9c2d75a955

View File

@ -1,9 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 987814f874125b118371952a4d882da2c78ee2c441d8fb228372ec0c8f2c5aad
initial_ast: 5ad90e127767873141d0ffb7aece1ea35cf0596a4af53a4445de27913896bef8
unrolled_ast: 5ad90e127767873141d0ffb7aece1ea35cf0596a4af53a4445de27913896bef8
ssa_ast: ae242f83b3e82979d257a6836ba17250486777f637807408ecd74bfa3f6424c1

View File

@ -1,9 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 7f94df9586954921fa1d2a86514669de35d102d4544fde34645d042810684363
initial_ast: b040faf711350fd0a4d5a0f2d24683f3b276cf1e602ed068a419c619bd98b415
unrolled_ast: b040faf711350fd0a4d5a0f2d24683f3b276cf1e602ed068a419c619bd98b415
ssa_ast: 3c46e4cb77e816db36878101b84ebba44b6f832620834b9ad79972cda5ab7f76

View File

@ -1,5 +0,0 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [EPAR0370005]: expected -> -- found '{'\n --> compiler-test:3:17\n |\n 3 | function main() {\n | ^"

View File

@ -1,5 +0,0 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [EPAR0370009]: unexpected string: expected 'formatted static_string', found 'hello'\n --> compiler-test:5:17\n |\n 5 | console.log(hello);\n | ^^^^^"

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8d6ceebb7eec5992baf2e10dd8b859dd823a066e40289d5fa2a3df24a0dc56f0
initial_ast: 8903fd80b2bf02ed5e96b14441b83d69a09ccf670961ab5213cc2f5e131684db
unrolled_ast: 8903fd80b2bf02ed5e96b14441b83d69a09ccf670961ab5213cc2f5e131684db
ssa_ast: 34934d9d302a1f80cb9ee60fb1f59e74447f4e343aff1590eacd839480033b60
flattened_ast: 97bc52775c1f822ccc2ce947e6fac88e31bf5af2abd960016c8cae8497fd9142
initial_ast: 7755af48fa14f5417f90b6fb47183c13e1e7cad87f03f29d42392f4ed7bd9148
unrolled_ast: 7755af48fa14f5417f90b6fb47183c13e1e7cad87f03f29d42392f4ed7bd9148
ssa_ast: 4b709f402c946a428b40b34860589ea14be881b4c070f77e45f19184092936cf
flattened_ast: b7672e04d6dc9bb26d9eaf5204b1a916d7dd9650549386df261c9fc8da2750d3

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 63a3ca615379adca59155029f240686c68b95ad4885f23971dffba3444880f46
initial_ast: 7849140c0e36a400e527c807b6d64b68ec0b862f5f3669763a2fa30fdcb7367a
unrolled_ast: 7849140c0e36a400e527c807b6d64b68ec0b862f5f3669763a2fa30fdcb7367a
ssa_ast: 47dd7ea513bd2a911f75cca9a49a87a827f2a222b3c4efeda6e4f5362c7277ad
flattened_ast: d41851bc8eb88d9b2bd825f6e1b5f29e20d12e92e35e482b9a4e2a862149337d
initial_ast: 810699ddd2296418131f85e365a05a658f5465b60a59d8d3c7f1b4a26f3ff53b
unrolled_ast: 810699ddd2296418131f85e365a05a658f5465b60a59d8d3c7f1b4a26f3ff53b
ssa_ast: a42d38d13dd2122f19d2c1b7d53435435bce745375bf5c34b36b6f1777bc9443
flattened_ast: ee52d27410e90f82ef478fa07287784c8ca0cc0d5ce42bb8497f10d41e2f819d

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8762f4e3aa37b05e762fbfce76fe6904854e68b4f6c41b3151f2c472c172a50a
initial_ast: 58354a3f130aec878f279494196abb9be21000e78e2ef07d81993cecba7012ee
unrolled_ast: 58354a3f130aec878f279494196abb9be21000e78e2ef07d81993cecba7012ee
ssa_ast: 1576837d18755a2506a96b7ff6fe1283a39c21e1517a1042200a2e46bf71a5da
flattened_ast: 8c7685683d896be857be3a6e1a0083433da0018de9fae4c2fc35729c0e968a43
initial_ast: 7796c77f0ec58a43c13a2f8687d332dd8b2a7934a9a8be13652d5c9dca96a791
unrolled_ast: 7796c77f0ec58a43c13a2f8687d332dd8b2a7934a9a8be13652d5c9dca96a791
ssa_ast: d30f3848317014603ca50f5c84e452bdfc79c00c99bf1f36631a7b2dc0851f43
flattened_ast: 402c17304ff28f7fab7bcb5a8bd8dca98264f38d92ec1646bafbc5a6593b8ec3

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: b638b226aa80d9c8720c2abc5fef167a2903a7e46c0a15a10d85c9a9bf73ba13
initial_ast: acf1332b3e50018dd9c08f0e2eeed37a1c5a0f08aa8ee5150992dcc51ec4703e
unrolled_ast: acf1332b3e50018dd9c08f0e2eeed37a1c5a0f08aa8ee5150992dcc51ec4703e
ssa_ast: b64d34803f1cd84be4335ae4b73ebb75415d195fff8638845f02c27512d74d6a
flattened_ast: e3a01e1c1960b51f05f9e364d48ac27d854e8e7a67cfdaa963a4f5d7a604de1a
initial_ast: e3400c48c510d33df5b886ca06d03fe0ae83e890624cb0d4711a0ab0802987f4
unrolled_ast: e3400c48c510d33df5b886ca06d03fe0ae83e890624cb0d4711a0ab0802987f4
ssa_ast: 9f5ad967cc8e49e4b88def2bf82ca153613df0777ba01bff0c3dad3bb0c012d0
flattened_ast: a1d8289fcfbecad1b22dd5c27cb45a75581e5d04d099fc9ad60ce138ca4562b4

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8762f4e3aa37b05e762fbfce76fe6904854e68b4f6c41b3151f2c472c172a50a
initial_ast: f2c00b12d62a178bbd497d3b97e8c82524b7017841b4981bdb22c0659c424ae4
unrolled_ast: f2c00b12d62a178bbd497d3b97e8c82524b7017841b4981bdb22c0659c424ae4
ssa_ast: 2a7ea14ba791f357e277f0a2a1d8f787eddfb49dd34ddec1666f3ff555bc5e98
flattened_ast: 9c88fbcb38c6494f4b5ff3d418b9dd69eb9fd739469bf3080edb4f6407b30a4c
initial_ast: 7103a45a5480a7f30dac3d08f4d8bd103ee4bd09728a4a8bc72e055e7e82290d
unrolled_ast: 7103a45a5480a7f30dac3d08f4d8bd103ee4bd09728a4a8bc72e055e7e82290d
ssa_ast: 2727a59b3d316203883ac50184dc5302f0457073df9c18dca3c03f5397c35544
flattened_ast: f847f470fe5e31816f55b855f8424dac03e9fea7f2691814554dc0364b7dfa2c

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: b638b226aa80d9c8720c2abc5fef167a2903a7e46c0a15a10d85c9a9bf73ba13
initial_ast: d42dde2e874e4f99efd01efe1e4961f61d6f8cff46e30c038fbd0a3735e00bd3
unrolled_ast: d42dde2e874e4f99efd01efe1e4961f61d6f8cff46e30c038fbd0a3735e00bd3
ssa_ast: 2b365232f1fb9e7dd576fa2fcb172d86f058be4544f353b96ddb6ceb9e245379
flattened_ast: 6c6dd818ff24551f5f36e704f476247308f5afe578c1aee16712c7c8409fdeff
initial_ast: dfd7aa65428709ddb83336f29a0aa7c4562e52d4855ca12b76203bfec52c2d23
unrolled_ast: dfd7aa65428709ddb83336f29a0aa7c4562e52d4855ca12b76203bfec52c2d23
ssa_ast: 0ee87241ef943f70de6d75bfe531f60c7542d3cb17318c5d0f12d5011a6bc014
flattened_ast: 29711b6b312e9495ab5d0044e369f98634ee1a962b82958aadac245b3ddfa390

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 8762f4e3aa37b05e762fbfce76fe6904854e68b4f6c41b3151f2c472c172a50a
initial_ast: 9826202bb36bcfcaa5d89d31de7c26a8e17bdcb1f858c924272c7b781e7aa1c8
unrolled_ast: 9826202bb36bcfcaa5d89d31de7c26a8e17bdcb1f858c924272c7b781e7aa1c8
ssa_ast: 71fcb33cb7d7af8f6f92c24e252973c0d1f062c09644a5326f4926ac86a5476b
flattened_ast: 1bc3c6d850b3b9ea858cc44206cbfae54b5c082eea6500ea248e2ca263c8bb5c
initial_ast: fd40b8ebbb75b41c1b6b7ad11b3a3c32faf08b31fe5b96270b1d28f95bb99a5a
unrolled_ast: fd40b8ebbb75b41c1b6b7ad11b3a3c32faf08b31fe5b96270b1d28f95bb99a5a
ssa_ast: 65ec356acb6ab71462925da6226ff2e0842d1e8421e70ab476801c0ecc24c52e
flattened_ast: bab304fe421d35178e0018cc513e4f25b5ce69cf8bc9d1bf01b20ea6161ef929

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: b638b226aa80d9c8720c2abc5fef167a2903a7e46c0a15a10d85c9a9bf73ba13
initial_ast: 142d39ab2813fecc19a096468315f242e72a9c586d1532fc96386e107678b47e
unrolled_ast: 142d39ab2813fecc19a096468315f242e72a9c586d1532fc96386e107678b47e
ssa_ast: 4c518161bd0e20e4fa6de1750fa52a62d07a09b8b93427257644d7a7f869c919
flattened_ast: 7743fbb072340a5e48e4ce17c240b1e73198cae3a0bf635edc465afec96094f8
initial_ast: 1f15a920d9eb3128245064ee1ff19fdb6e5dc0095ad67ec6e791b121cb98c265
unrolled_ast: 1f15a920d9eb3128245064ee1ff19fdb6e5dc0095ad67ec6e791b121cb98c265
ssa_ast: 8e72da7f56ae155a4a9b05f5cc51c18edf77b90e51122742b5164862397ef818
flattened_ast: 9924bdd85dd2ace14e0830f91650fa71b51203a863116dbada0100a818b9d8b8

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 5ea1607a031b1eaecb1b6aac13dae8c78f3fc15c5f9c7d8db94001539426f7eb
initial_ast: edce2be4d936b46d3d6601182db3463a7c0153bc7f7bdee70d1ef472bb64fcf3
unrolled_ast: edce2be4d936b46d3d6601182db3463a7c0153bc7f7bdee70d1ef472bb64fcf3
ssa_ast: 30974184b79ce16214677e84e1d35739b030359f7472e02256a803259cd43481
flattened_ast: eab2a17522833f8e9b0a48b87434e6340b7daf61b4cb32ee0d8212703986edb1
initial_ast: baeb24b1f31b4aa82a6897fa17042f17fc3d3488010763ae7d51c53735fa6687
unrolled_ast: baeb24b1f31b4aa82a6897fa17042f17fc3d3488010763ae7d51c53735fa6687
ssa_ast: cb68431db2ab894183ea0c2ab10763d5ff248dd38e6357d2d0727283fb523b2f
flattened_ast: 32dd2281edd7383e8699c7b011a7f70ae2ac51d7096e6524a03e515da1d43c3a

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 43e7c413d898dd18070456e6875adbf73a93f3cd2703fc7f6bc7c793d8063bbd
initial_ast: a2eab8ce0e64bf860f4dcdb417456472ae3e6ab589f10671610bfbc9d6286daf
unrolled_ast: a2eab8ce0e64bf860f4dcdb417456472ae3e6ab589f10671610bfbc9d6286daf
ssa_ast: e319d34bc5f262473ef97591576d27331dba26c8973efd22dfeb61d799b0916a
flattened_ast: 23e2785a4e80347990da3ed6734fefe1c6268ff152ca70f2fdaeddb075c296cd
initial_ast: 73f059d09937d69534aeecb3c2e1e85926eaec2d6b609a303d32a9b44e2e2996
unrolled_ast: 73f059d09937d69534aeecb3c2e1e85926eaec2d6b609a303d32a9b44e2e2996
ssa_ast: 109520afec3da0053b566aaa754dee1ca6a492bcf3d92ef389d5bac80649a664
flattened_ast: 5293dfaaa403841e50f7851ac74055e7ac96155ed8641134c739e05a75144fa1

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: e3f5a66af9a0c987403e9ff8c0e084c127a374827259aca0e5b8f877a72700cf
initial_ast: 3854d622a8991b3f900e9e77c60950c14541a9cfa13ff28914a1367e43cedc83
unrolled_ast: 3854d622a8991b3f900e9e77c60950c14541a9cfa13ff28914a1367e43cedc83
ssa_ast: c82824e8ef89e7aedd84a7aa0e958044f3a7b763a573a0977d2ea7a0cba9289d
flattened_ast: 39803ccdd17079915cc9b899419fce48775f1cfe2d15040379ca1b0fa5008beb
initial_ast: c9d9523624ef7ef1f2d83802edf9b74864239d1161337f1e8f65a1ed337721c7
unrolled_ast: c9d9523624ef7ef1f2d83802edf9b74864239d1161337f1e8f65a1ed337721c7
ssa_ast: 280bbfb0de512b77bad9b62dfb4bb883ca744edda97957df2336c4a52d2e38f6
flattened_ast: 03e0b32e1c56093aadd4a1af4ac3b0f3d398b756a10440594e62cf2c4bc01240

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: e4ca07cbf83cbb0689e77f23f535f3e207b95e02ced7b97c0e54181109e4e435
initial_ast: 31b03ee1a972ed7ff5af17ff19daa091ec7ebbb4cb8e04dc57cd300bb5dde887
unrolled_ast: 31b03ee1a972ed7ff5af17ff19daa091ec7ebbb4cb8e04dc57cd300bb5dde887
ssa_ast: 278b4c43b0cd54c4781f17024baa960961fe58ea0deb3ccfb0330760ab518649
flattened_ast: b25e798d5951c3f9133fb1a793f8950dc6128aca49149175800ad740c3167e55
initial_ast: 9b31d4f47de0c315601754df1f7460938a382a4de56aa7b3b285c2f4004583e5
unrolled_ast: 9b31d4f47de0c315601754df1f7460938a382a4de56aa7b3b285c2f4004583e5
ssa_ast: 85649cecc12100009fd032e3d8f4b7a1e1f14abd50f4a78de691e02bfad6dcef
flattened_ast: 1ee55ed5def4045f0a4790efa8e3fb73b5816c3ce2d5f47cc3bc13ad2acb353d

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: bd66a8c48fe434715d1d19ca0c60e77b4f2b8ec92f4b0a785277774a2074a804
initial_ast: 22116947f0e502345f67deea4376392a6d5a7a1c147dcd4d58d3bda0ddfb245b
unrolled_ast: 22116947f0e502345f67deea4376392a6d5a7a1c147dcd4d58d3bda0ddfb245b
ssa_ast: ee76b847a759607f4ba1f4e896b67434442e0af2f7e666c14cbbed9c3a6c0086
flattened_ast: 4ba31b085167ff9a5ec622d5a41e21d8443d767046795d1545a26cbd3655e639
initial_ast: 26c0866267e8a0fc6906f8a3ae58065d25eebf680203bc6389279a994a36bbd7
unrolled_ast: 26c0866267e8a0fc6906f8a3ae58065d25eebf680203bc6389279a994a36bbd7
ssa_ast: 93a00777cab8fd569c02c1912bde13423ba76969fda194cfb90d53c33b7b7d62
flattened_ast: 6ce624bb4854f15c293eb1bf648c7e78eba27170967d6ac256882521a18a6714

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: bd66a8c48fe434715d1d19ca0c60e77b4f2b8ec92f4b0a785277774a2074a804
initial_ast: 992d7b50e675edb82bcbad04d90276b8caeaccd815aea3eee972589e4bfb789a
unrolled_ast: 992d7b50e675edb82bcbad04d90276b8caeaccd815aea3eee972589e4bfb789a
ssa_ast: b4defa34c9d548db0f4cddb89da478b4ddf522227d8edb513fad7b6ff09451fa
flattened_ast: 0c0ca9e6d949f089e03fea84caf72d5ac1ccbdbfd10ae169fd5fff5032d6d166
initial_ast: f6b19cef14fa836f6819cf82f8d9698f6de23b53ceac435c87ce255e513fff67
unrolled_ast: f6b19cef14fa836f6819cf82f8d9698f6de23b53ceac435c87ce255e513fff67
ssa_ast: 5852258fec031000d4718bda4fd974b3a2af7d732110b243fa8fa32e84857329
flattened_ast: 92ce201c50776daf40223fa264a5192fd09fc622041595f3609b62e6cd98b4a9

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: bd66a8c48fe434715d1d19ca0c60e77b4f2b8ec92f4b0a785277774a2074a804
initial_ast: f6c4fd99998e9c3bbd97aa8778435493b4e68cdb60fe21d3a5dcb1251225c5f2
unrolled_ast: f6c4fd99998e9c3bbd97aa8778435493b4e68cdb60fe21d3a5dcb1251225c5f2
ssa_ast: f4aa21d116f7f2043d0acce34d88a0fd36dc6c341ea1a453490fd58774ebaefc
flattened_ast: d2d42db9bcdefdd583835d4b4f774f37515bffcd47194c34736cac8ef1dbc228
initial_ast: 20fb9299a9f207d435ea934cbd422d55d59dc9f0eecc36cb8e4f1bbe69ade5c4
unrolled_ast: 20fb9299a9f207d435ea934cbd422d55d59dc9f0eecc36cb8e4f1bbe69ade5c4
ssa_ast: 6a87bf46edb6e628df6e90b0b047d1b73d8dba988fa95c78b5e90b125a881d33
flattened_ast: ef158133de6b391389947e54e61fb8891f4288296b3a84bf98208126cf3b1c6a

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 19bd7efeaa5dee077b8d47a087ceadc2ba287507268fd8586f4e6f5881b71c39
initial_ast: fa924a57d700de68e1ec3250bba4d5b66f05c4404d9fccc3821928a3296a2ba8
unrolled_ast: fa924a57d700de68e1ec3250bba4d5b66f05c4404d9fccc3821928a3296a2ba8
ssa_ast: 688654fb76e7de8d9af8b5e7071b6b5fc3c641be793125b7144657eb8ed20d13
flattened_ast: 5d79e9163a1b400164035e9a57f73452ee1b6a19bcdf39f0df6f84b82d62922c
initial_ast: a89c4aa81cb743f8c9e39e52164d0022f8c9992afb8447c3d92503779227feeb
unrolled_ast: a89c4aa81cb743f8c9e39e52164d0022f8c9992afb8447c3d92503779227feeb
ssa_ast: 73adc4582ce761cd706c31116e715c055339c4d6e93558a0692c0f0d2bfc1901
flattened_ast: 326a9ba3e0a88d4b791741fdf4c5b9e1ab3238e3035897a7dad2cf59e29c0491

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 38e152ef2d3449f93d8c1858a916854228a76dd18885b01cb4a88c14d84308bf
initial_ast: 628cfcf0a7118c904ab9a439f7b8ac2b08bd3cb10a279c063a1a3b06f90a2a23
unrolled_ast: 628cfcf0a7118c904ab9a439f7b8ac2b08bd3cb10a279c063a1a3b06f90a2a23
ssa_ast: 3c1b3bcc67a6e0dc844db16acab349d5062eacea4f5a2ae20ad87703fc99f2f3
flattened_ast: 8cbd286f80ac99a06f7e1036e2f6003cccdea160976fc8a871737fa06ca28469
initial_ast: c9acdeb2f208ff412391a81e9889a792a03d205eacc0ce34ecc4ea5e51d1058a
unrolled_ast: c9acdeb2f208ff412391a81e9889a792a03d205eacc0ce34ecc4ea5e51d1058a
ssa_ast: 4b8c3dec168259f154f4843715c941cb69a3871eab56e1b0c6d887c0372ecdbe
flattened_ast: 3cd47d58daa5dfc91ddfefbe8ac9894dbdd03342256f1b133179059db36927fa

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 413788ce5f6dc8aa19af5360bedfca93c33a2a6464ede476e59b75e84a8a4e4a
initial_ast: ffb7af0061b540e44f78074c007cab0f1024bb6fdf4378023852091cc0004dfe
unrolled_ast: ffb7af0061b540e44f78074c007cab0f1024bb6fdf4378023852091cc0004dfe
ssa_ast: ae3042732a5634b573b186c5d4ff4f3ab44826f80cc2ab56502fd1f5ba6798eb
flattened_ast: 6405e7d5970889065c3723a8c5ee9372d976895fd01a93e5aeb065e7fcf7e228
initial_ast: a16185f52d2f134eb1bc83861f7b39c98643f5cfd606162cad77c5f289b2c2ff
unrolled_ast: a16185f52d2f134eb1bc83861f7b39c98643f5cfd606162cad77c5f289b2c2ff
ssa_ast: f32d13bb403718640f27796d03629ce52df97f0dc118216740fd64cb0b5f03fb
flattened_ast: 9ed30a1845263307b94893d899599ceacf5a38be76056701e539c3a6d248f042

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: d88a843c0a3851c805f7eeae282a16b12eba4febde134aa0ea86415f6561565d
initial_ast: a8258c9fd04f95521349955f7a6180e25054bc5e984c7b2fc1e412ae1f516bbd
unrolled_ast: a8258c9fd04f95521349955f7a6180e25054bc5e984c7b2fc1e412ae1f516bbd
ssa_ast: 90934ba26a01d3be3d4e884120033e27f7f296750def5c0654b7fce651a3ef7c
flattened_ast: f56c9ba1a0c50ef0dd3eeaacb3cc757d49ea99d8c861284ffeb90c758eb43db3
initial_ast: 55576dafd5e447c30ca8a9eedd2732903d7781dd4384894b7f37bdd7773f3339
unrolled_ast: 55576dafd5e447c30ca8a9eedd2732903d7781dd4384894b7f37bdd7773f3339
ssa_ast: 22d4a8aa55dacc1e06e515ea9afd92c164fb779864daf720c170ff46adcddcf5
flattened_ast: d1a43581b7432032ed765bcd6795323bc5103d42505b7852ea3256739d9ea642

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 1bd243c2ca8a51ee50f45823a283d506ee506e168e5332af8c271ef6b52468a4
initial_ast: ad6b130a938f0dd5155f90e983a7214c374c497b8c1e00cee75ccb7e763f257a
unrolled_ast: ad6b130a938f0dd5155f90e983a7214c374c497b8c1e00cee75ccb7e763f257a
ssa_ast: 7f6d8438a23f92d9330b8d7e66df96a73e21fb3145b7a9500d2010e075092e5b
flattened_ast: 862d1165b3c7226dfa5dfecac9bc5a24e5bcc6633fb8d08d1eb71b935436b52d
initial_ast: ca07155862559dcbcd8a9df352440d2f1b0cb3071004afc8418ae6f5b25b4ce9
unrolled_ast: ca07155862559dcbcd8a9df352440d2f1b0cb3071004afc8418ae6f5b25b4ce9
ssa_ast: 4e17bb648d103c6438c3c5776fd7157018c0139016d561de21a8768d7f9d5538
flattened_ast: 9b4cf2b763504d9d1d0c143145ec9bd27195d973b872079d319ffaee6a6210ec

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 38e152ef2d3449f93d8c1858a916854228a76dd18885b01cb4a88c14d84308bf
initial_ast: 21a67a09172cc2d79d483c7ab97a5a38ed8e132fb362116d2dae237323d0b67a
unrolled_ast: 21a67a09172cc2d79d483c7ab97a5a38ed8e132fb362116d2dae237323d0b67a
ssa_ast: f3d5d47b6b4588ef0908f272dadc91e834e9dfd9e075c9680bc6942064871f3b
flattened_ast: 614cf33119a13bd0d119940508582276fba62ec5d20cbc59a49ba0f73c39bfaa
initial_ast: 25c34196a4c6cf173abcfbe96d4639c86613daf52628b0b93d3ab81823923c98
unrolled_ast: 25c34196a4c6cf173abcfbe96d4639c86613daf52628b0b93d3ab81823923c98
ssa_ast: eb1e51c0f21d76621d2c9ac6c2c68808e5c62b71dd8678b60e4e14adc8a640d7
flattened_ast: 462a11d950a3aded9e17de27c105b3d6a7a194299f6ac017eea30b37e65817c0

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: c0c942faa92a5c747fab2d776e6dd0067de317c69003493147610a09878843c4
initial_ast: 89a950aac426837a580bde73fc49d51dabcd39a167f43f4dee74a0ffa0aade3f
unrolled_ast: 89a950aac426837a580bde73fc49d51dabcd39a167f43f4dee74a0ffa0aade3f
ssa_ast: 6f0bfcd1860dbdcbc23040af7d352071f3053ca30c8c0b4b8ecdeef34b6298b3
flattened_ast: 2d249b0b10f86062157324741829894c0456bfca51237b68e9b5fab8b7aac51d
initial_ast: 246d9f598a2420e00b4e3d42ddf69040e31cada19e6a10c8f00fd3c5736cc566
unrolled_ast: 246d9f598a2420e00b4e3d42ddf69040e31cada19e6a10c8f00fd3c5736cc566
ssa_ast: c25b4ee0ddabe79a2df19b021cd6e73ce0f3a2f371560bc3a2111ae526b416be
flattened_ast: bac91a0a759bf24fe756eba8c967e64430d2cdae364550b1046972b4f952c74f

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: ea8e9817122af3fa825b175438a1af4943d31c5c893a3af31b96964f80ec5850
initial_ast: d15977d2a3812dfab405f8cf8e4c433739f01c47c8e09b8f5cd336970e903c24
unrolled_ast: d15977d2a3812dfab405f8cf8e4c433739f01c47c8e09b8f5cd336970e903c24
ssa_ast: a66f5b52e55ce6aee628567a23c0aa117737953ae04f27d4225a38675cb85dfd
flattened_ast: b84e80bbcf1ada93dac226719598f58acca65cb043b9e9742bf5db23c3b9150a
initial_ast: 1acd222d2540f9e6a51328da90ff6b90fe0ebbd799a194e9281244a2cc3a5bf2
unrolled_ast: 1acd222d2540f9e6a51328da90ff6b90fe0ebbd799a194e9281244a2cc3a5bf2
ssa_ast: 766725b5f9b3b0578f46c4ad6c71a45da1d649409a00124e44cb09ad57a4914b
flattened_ast: df0ab0f368c765ddddc8254870ca552cf454e8166c2e1ef146a99fb131d14dff

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 30267abd65849fc218532e602d0e60eefb1dd235972106400258e3d9e54c2c10
initial_ast: f2caf99b19f3d57ac03d5f051206cab69ac40dd07891e44b09c64affb7658dd0
unrolled_ast: f2caf99b19f3d57ac03d5f051206cab69ac40dd07891e44b09c64affb7658dd0
ssa_ast: 40de64d16cd1574dee019f40a50207e16045b96e21116b315fb76c5081debb38
flattened_ast: 7a13ea9790d3f7b1606344d47115d9e2270762ca99e81e025ec8a9d4e5901376
initial_ast: e8aff155e0e2df199f735fde15c2c83fcf885867fc3ba9a7f27ad09beeaaeda3
unrolled_ast: e8aff155e0e2df199f735fde15c2c83fcf885867fc3ba9a7f27ad09beeaaeda3
ssa_ast: 3f3f8da4d645c04d2ba4272012106b9fdcc6d76c64321c4d8d0bbdb49fcdd7a4
flattened_ast: c49bf9a53a2cf0c0c87f95d79268d95f6ff9d2ef5167f28615cc860247fe4d3b

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: 413788ce5f6dc8aa19af5360bedfca93c33a2a6464ede476e59b75e84a8a4e4a
initial_ast: 04d6f99bfb619e3ef30beb1c8182a6c38afecbecd39bd10b49424feabbd49814
unrolled_ast: 04d6f99bfb619e3ef30beb1c8182a6c38afecbecd39bd10b49424feabbd49814
ssa_ast: 5d584c4d01f1a3e7b255250829dc170d34ed43952cdc098a4f7666d052a45771
flattened_ast: 312295ab386878c3ecb6f2ca267da0662ba4f9b1cadf761e253101725993ef14
initial_ast: 57fa51e0ed71fff7bc2601b90d506293efbdb0b4b7155b65feed8e8c6682609c
unrolled_ast: 57fa51e0ed71fff7bc2601b90d506293efbdb0b4b7155b65feed8e8c6682609c
ssa_ast: 9ffa84a1979072a17ab2358246b47e2629e3f15d051cab15d4c70577701f4a4e
flattened_ast: a8ac0f95f6ef0c6f1e4df7313b09f9117bcae2e8930fce9c52dad3ed208b79ce

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: e0d887adc24d86b1ddd1b6b7fee99e39c4def4850dc6afa7765a2d45089d39cd
initial_ast: 01a8cd34a5f5e06c35d0687d5e552ef56058d9b8ade32d5c35602028b1d71483
unrolled_ast: 01a8cd34a5f5e06c35d0687d5e552ef56058d9b8ade32d5c35602028b1d71483
ssa_ast: 96f77e5aa7b01f8afe5679048eb7bb9567473a72095bd690f6a3a7636e6b2b15
flattened_ast: 65683c8b503159cda6a4c47c5c0f9ab4e6afa7c4bbf82ce6028e46a844055007
initial_ast: 6f0badefc2b52349c6ba3aaf16dc9e911668dbf04d42d6fa9ddd6a40aa7374cc
unrolled_ast: 6f0badefc2b52349c6ba3aaf16dc9e911668dbf04d42d6fa9ddd6a40aa7374cc
ssa_ast: a8f7e053ccabac1b0183febfda356f5c12981298af5a23380d61cf704d92db5a
flattened_ast: 95bc317c202aa857167f545409663d20de720485398b61acfb1f73db45a60e9c

View File

@ -1,5 +0,0 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372036]: Cannot use a `finalize` statement without a `finalize` block.\n --> compiler-test:4:5\n |\n 4 | finalize(a, b);\n | ^^^^^^^^^^^^^^\nError [ETYC0372044]: Function must contain a `finalize` statement on all execution paths.\n --> compiler-test:8:1\n |\n 8 | function bar(a: u8, b: u8) -> u8 {\n 9 | return a + b;\n 10 | } finalize(a: u8, b: u8) -> u8 {\n | ^\nError [ETYC0372032]: Only program functions can have a `finalize` block.\n --> compiler-test:10:3\n |\n 10 | } finalize(a: u8, b: u8) -> u8 {\n 11 | return a + b;\n 12 | }\n | ^\n |\n = Remove the `finalize` block or add a `@program` annotation to the function.\nError [ETYC0372032]: Only program functions can have a `finalize` block.\n --> compiler-test:17:3\n |\n 17 | } finalize (receiver: address, amount: u64) {\n 18 | increment(account, receiver, amount);\n 19 | }\n | ^\n |\n = Remove the `finalize` block or add a `@program` annotation to the function.\nError [ETYC0372005]: Unknown variable `account`\n --> compiler-test:18:15\n |\n 18 | increment(account, receiver, amount);\n | ^^^^^^^\nError [ETYC0372004]: Could not determine the type of `account`\n --> compiler-test:18:15\n |\n 18 | increment(account, receiver, amount);\n | ^^^^^^^\n"

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: e4d86cd0b7831c3de0304190f5af8f1ef7d8e29d1bdacb6d35381ba0e479d6ab
unrolled_ast: e4d86cd0b7831c3de0304190f5af8f1ef7d8e29d1bdacb6d35381ba0e479d6ab
ssa_ast: e4d86cd0b7831c3de0304190f5af8f1ef7d8e29d1bdacb6d35381ba0e479d6ab
flattened_ast: 0ba4b1ecf6e5ebe0c7b7ed0ba10d9830902d7a492c2000fef2cf67e4b43b063a
initial_ast: 9498c048747706d4478783a2801179d84243099c3867cb437f4141bf873fc381
unrolled_ast: 9498c048747706d4478783a2801179d84243099c3867cb437f4141bf873fc381
ssa_ast: 9498c048747706d4478783a2801179d84243099c3867cb437f4141bf873fc381
flattened_ast: 30e7fb13033f0a61d999026dbeafff5fe3938e4b6ed2cb709fc0a38ce98c8c57

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: 8d3492275b704c017c6b9053d267e54ac3374934423cb2b8c5e55bb7e8ecc033
unrolled_ast: 8d3492275b704c017c6b9053d267e54ac3374934423cb2b8c5e55bb7e8ecc033
ssa_ast: 6c17d90ec3d2b7acf165ca2ab04e30bf8a49cb3d110ee38e7130eeaa9b0754ee
flattened_ast: 4633594269a408f79ac385ab5d4b41b2b8b9cc69c29ea6d96761be5bd64fe2ef
initial_ast: 4fcaf4a3cc781ca66c4ed30d4704bfa5bc31715a9cce6c12c3b45ba13deebb5c
unrolled_ast: 4fcaf4a3cc781ca66c4ed30d4704bfa5bc31715a9cce6c12c3b45ba13deebb5c
ssa_ast: d511fa6a72cca8b7370691502a92837faac71965312b63e55ce372271720612a
flattened_ast: a085ceac6974fb2a2cbf32de9775e0dbe3c1ca1e1ad184141a8794df6f7bef32

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: 743ef643d0205706e875c7eb3a4fc5866e8a3e6b6c43388c36be418a0f37773c
unrolled_ast: 743ef643d0205706e875c7eb3a4fc5866e8a3e6b6c43388c36be418a0f37773c
ssa_ast: 743ef643d0205706e875c7eb3a4fc5866e8a3e6b6c43388c36be418a0f37773c
flattened_ast: 7678967d822f0d82683ca4c01410377bd53e3ce78da126d0c07b651722c23be4
initial_ast: 20577705e80224f486f237ba98fb33550fec7fb0a724eb9c339067a561d426e6
unrolled_ast: 20577705e80224f486f237ba98fb33550fec7fb0a724eb9c339067a561d426e6
ssa_ast: 20577705e80224f486f237ba98fb33550fec7fb0a724eb9c339067a561d426e6
flattened_ast: 6babfacc82c1283848fc1926ca778d6a3c7a46148cfe93fec13927ed31bd950a

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: e742fe16a7df15d6f9c6b514f28746a9a5a48fda7e0bf6628601e84782878dd1
initial_ast: 9ff7652fd6e9f8eb98218202fb58e54821adba09548e1826382934d4c3a63ce6
unrolled_ast: 9ff7652fd6e9f8eb98218202fb58e54821adba09548e1826382934d4c3a63ce6
ssa_ast: 1f75b9481a40777666cc514bebec6847dd678229c3800e54211cfc36bfa6fc95
flattened_ast: 344e01d295321c1bfdbd4938d061e61c4f2785c37650eeab097a19ed129b2f28
initial_ast: 93f6ddf8a363f5846f4ea0be8a8ee9872b99244753cbb62f448a44f5ba1c3851
unrolled_ast: 93f6ddf8a363f5846f4ea0be8a8ee9872b99244753cbb62f448a44f5ba1c3851
ssa_ast: a9f3714757132157a0057d73a2a9b32e353e33225ca725ecdb7765cce7ed5eab
flattened_ast: c92cb99ac45cef4e57c5509164f694e5dfc83ce36f751079deb09f64043079fe

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: e0516243c09ed592d62da2f5db28b9c23d62a65a2d1d2f36994af7a5200ef832
unrolled_ast: e0516243c09ed592d62da2f5db28b9c23d62a65a2d1d2f36994af7a5200ef832
ssa_ast: dd25b1abb6b78fa6fac53f5d2c27d9b183728441b9a796a5b24e4d8be238e604
flattened_ast: 6a0e4a111f150fd817ba4ba9e4b507395fb7f79993c816ba0d0a8207b6b8ce9c
initial_ast: 5f0666623644b5df97e5cde9c2f83d697f42560b9c6aab3ff77b591ef6583726
unrolled_ast: 5f0666623644b5df97e5cde9c2f83d697f42560b9c6aab3ff77b591ef6583726
ssa_ast: e25f8b8ac74f74a74d4229341c046c8d05a07612bd2787d097cdd2ae02c7d57d
flattened_ast: e4cf9a17967fc3971f82cd7e1bec5a241794ec081d99b73b278022b236f14198

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: d25b5d30496f06387198d06e44a771e142f8e6592347c3849a8b3b957287f1b6
initial_ast: 1b616bafa5e8d7e18cb435f89aa62aa35289c5c8905053a74d496b3bb06b3c2b
unrolled_ast: 1b616bafa5e8d7e18cb435f89aa62aa35289c5c8905053a74d496b3bb06b3c2b
ssa_ast: 95d5f10d34e333921b12624ee57d50e965ae6c28ec576da7e46f0083df2f6e8c
flattened_ast: 261ec4ae28babea5b332c340e87275bb78139d5ed3e7fc619c7618638ad32cd7
initial_ast: b719757474b3ca863d3589924673e4e9074570fe1b95bbc08ab1c9ddece99810
unrolled_ast: b719757474b3ca863d3589924673e4e9074570fe1b95bbc08ab1c9ddece99810
ssa_ast: 833917e3a7251bd51c4572068c44fb86eefc973a38c4931a762817d94bfb739f
flattened_ast: 3d8bf8350b63dd967ca2af254b3ceaa77e5c197d40f79354a6591500f2a8a695

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: aa1909b07d93826301b19607129d9ad58c8fed3666d19a3a8c7d5e6cabd4a784
unrolled_ast: aa1909b07d93826301b19607129d9ad58c8fed3666d19a3a8c7d5e6cabd4a784
ssa_ast: 74728731fc75c801b3b5cf5d9e568f465b0ee0e881947a6420f98cc8766aeb8b
flattened_ast: 4d2bcb0ab5e016ac03baf3014ad284206671ad93b1b121ec063cfde3cc681c9b
initial_ast: 9ba8e38f07e0d133ee261029fee8cd25de5f96266aafc0818331c32005811270
unrolled_ast: 9ba8e38f07e0d133ee261029fee8cd25de5f96266aafc0818331c32005811270
ssa_ast: fac7c287e7a169ee00ffcb5c2595baaa83f3a278f56b916a326689fc28c13fef
flattened_ast: 79f8da1f08d9a0ef53d222eac163d59eaf9a0d54d3c72f7dc75a0bc7947ce16c

View File

@ -1,5 +0,0 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372038]: Function must return a value.\n --> compiler-test:3:1\n |\n 3 | function main() -> u8 {}\n | ^^^^^^^^^^^^^^^^^^^^^^^^\n"

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: b00084908a0b08097b22f8f05d51960654857e02955744b489d6e65a626631af
unrolled_ast: b00084908a0b08097b22f8f05d51960654857e02955744b489d6e65a626631af
ssa_ast: cfbfe34e206a21d620942225fac473873d3b19ce8ac7cdbf35d5416aa6845f33
flattened_ast: 090fe1adcae13655d8e3909ab9044b66d4d13a9688d1ad8259cd76aed7cce5c5
initial_ast: 2ffe06e486343ec47a09a4d3f88413f5cb9e5f4acdc1ae6160fc6bc68f09ea08
unrolled_ast: 2ffe06e486343ec47a09a4d3f88413f5cb9e5f4acdc1ae6160fc6bc68f09ea08
ssa_ast: bf465100cd883d58a7ee65375addf869c7c8048601e50dba2fae60a5ebe89979
flattened_ast: 307ca5456c46e1d42eb91eda8a70f02983381bfb8eaaa2a43e295595c0f17d6d

View File

@ -4,7 +4,7 @@ expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: d00c57417aab0ef501832ca09df8aee8d06b2d90c98e9eaa6220bc9d03bfb13b
unrolled_ast: d00c57417aab0ef501832ca09df8aee8d06b2d90c98e9eaa6220bc9d03bfb13b
ssa_ast: d00c57417aab0ef501832ca09df8aee8d06b2d90c98e9eaa6220bc9d03bfb13b
flattened_ast: d00c57417aab0ef501832ca09df8aee8d06b2d90c98e9eaa6220bc9d03bfb13b
initial_ast: cec556a96e40d2958f1338d14b17336f48459bcd7796656fe65a0d2f39e8d6b7
unrolled_ast: cec556a96e40d2958f1338d14b17336f48459bcd7796656fe65a0d2f39e8d6b7
ssa_ast: cec556a96e40d2958f1338d14b17336f48459bcd7796656fe65a0d2f39e8d6b7
flattened_ast: cec556a96e40d2958f1338d14b17336f48459bcd7796656fe65a0d2f39e8d6b7

Some files were not shown because too many files have changed in this diff Show More