Merge pull request #1996 from AleoHQ/feat/codegen-for-function-calls

Codegen for Function Calls
This commit is contained in:
Collin Chin 2022-08-05 20:45:05 -07:00 committed by GitHub
commit 7b739a35e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
726 changed files with 2593 additions and 1769 deletions

View File

@ -33,13 +33,13 @@ Contains the Circuit's name, as well as its members.
The members are a function, or a variable, or a constant.
For all of them the Circuit preserves their names.
#### [Decorators](./src/annotation.rs)
#### [Annotations](./src/functions/annotation.rs)
An annotation node is a decorator that can be applied to a function.
Stored on the function themselves despite being a top-level node.
The node stores the name of the annotation, as well as any args passed to it.
#### [Functions](./src/functions/function.rs)
#### [Functions](./src/functions/mod.rs)
A function node represents a defined function in a Leo Program.
An order-preserving map of these are stored on the Program.

View File

@ -14,8 +14,27 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
pub mod function_input;
pub use function_input::*;
use crate::{simple_node_impl, Identifier, Node};
pub mod input_variable;
pub use input_variable::*;
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// An annotation, e.g. @program.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Annotation {
// TODO: Consider using a symbol instead of an identifier.
/// The name of the annotation.
pub identifier: Identifier,
/// A span locating where the annotation occurred in the source.
pub span: Span,
}
simple_node_impl!(Annotation);
impl fmt::Display for Annotation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "@{}", self.identifier)
}
}

View File

@ -1,85 +0,0 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Block, FunctionInput, Identifier, Node, Type};
use leo_span::{sym, Span, Symbol};
use serde::{Deserialize, Serialize};
use std::cell::Cell;
use std::fmt;
/// A function definition.
#[derive(Clone, Serialize, Deserialize)]
pub struct Function {
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// The function's parameters.
pub input: Vec<FunctionInput>,
/// The function's required return type.
pub output: Type,
/// Any mapping to the core library.
/// Always `None` when initially parsed.
pub core_mapping: Cell<Option<Symbol>>,
/// The body of the function.
pub block: Block,
/// The entire span of the function definition.
pub span: Span,
}
impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
self.identifier == other.identifier
}
}
impl Eq for Function {}
impl Function {
/// Returns function name.
pub fn name(&self) -> Symbol {
self.identifier.name
}
/// Returns `true` if the function name is `main`.
pub fn is_main(&self) -> bool {
self.name() == sym::main
}
///
/// Private formatting method used for optimizing [fmt::Debug] and [fmt::Display] implementations.
///
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "function {}", self.identifier)?;
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
let returns = self.output.to_string();
write!(f, "({}) -> {} {}", parameters, returns, self.block)
}
}
impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
crate::simple_node_impl!(Function);

View File

@ -22,6 +22,7 @@ use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParamMode {
None,
Const,
Private,
Public,
@ -32,6 +33,7 @@ impl fmt::Display for ParamMode {
use ParamMode::*;
match self {
None => write!(f, ""),
Const => write!(f, "const"),
Private => write!(f, "private"),
Public => write!(f, "public"),
@ -41,7 +43,7 @@ impl fmt::Display for ParamMode {
/// A function parameter.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionInputVariable {
pub struct FunctionInput {
/// The name the parameter is accessible as in the function's body.
pub identifier: Identifier,
/// The mode of the function parameter.
@ -52,7 +54,7 @@ pub struct FunctionInputVariable {
pub span: Span,
}
impl FunctionInputVariable {
impl FunctionInput {
pub fn new(identifier: Identifier, mode: ParamMode, type_: Type, span: Span) -> Self {
Self {
identifier,
@ -67,7 +69,7 @@ impl FunctionInputVariable {
}
}
impl FunctionInputVariable {
impl FunctionInput {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ", self.mode)?;
write!(f, "{}: ", self.identifier)?;
@ -75,16 +77,16 @@ impl FunctionInputVariable {
}
}
impl fmt::Display for FunctionInputVariable {
impl fmt::Display for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for FunctionInputVariable {
impl fmt::Debug for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
crate::simple_node_impl!(FunctionInputVariable);
crate::simple_node_impl!(FunctionInput);

View File

@ -1,86 +0,0 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{FunctionInputVariable, Node};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// Enumerates the possible inputs to a function.
#[derive(Clone, Serialize, Deserialize)]
pub enum FunctionInput {
/// A normal function parameter.
Variable(FunctionInputVariable),
}
impl FunctionInput {
///
/// Returns Option with FunctionInputVariable if the input is a variable.
/// Returns None otherwise.
///
pub fn get_variable(&self) -> &FunctionInputVariable {
match self {
Self::Variable(var) => var,
}
}
/// Formats the parameter to `f`.
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FunctionInput::Variable(function_input) => write!(f, "{}", function_input),
}
}
}
impl fmt::Display for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl PartialEq for FunctionInput {
/// Returns true if `self == other`. Does not compare spans.
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(FunctionInput::Variable(left), FunctionInput::Variable(right)) => left.eq(right),
}
}
}
impl Eq for FunctionInput {}
impl Node for FunctionInput {
fn span(&self) -> Span {
use FunctionInput::*;
match self {
Variable(variable) => variable.span,
}
}
fn set_span(&mut self, span: Span) {
use FunctionInput::*;
match self {
Variable(variable) => variable.span = span,
}
}
}

View File

@ -14,8 +14,80 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
pub mod function;
pub use function::*;
pub mod annotation;
pub use annotation::*;
pub mod input;
pub use input::*;
pub mod function_input;
pub use function_input::*;
use crate::{Block, Identifier, Node, Type};
use leo_span::{sym, Span, Symbol};
use serde::{Deserialize, Serialize};
use std::cell::Cell;
use std::fmt;
/// A function definition.
#[derive(Clone, Serialize, Deserialize)]
pub struct Function {
/// Annotations on the function.
pub annotations: Vec<Annotation>,
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// The function's parameters.
pub input: Vec<FunctionInput>,
/// The function's required return type.
pub output: Type,
/// Any mapping to the core library.
/// Always `None` when initially parsed.
pub core_mapping: Cell<Option<Symbol>>,
/// The body of the function.
pub block: Block,
/// The entire span of the function definition.
pub span: Span,
}
impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
self.identifier == other.identifier
}
}
impl Eq for Function {}
impl Function {
/// Returns function name.
pub fn name(&self) -> Symbol {
self.identifier.name
}
/// Returns `true` if the function name is `main`.
pub fn is_main(&self) -> bool {
self.name() == sym::main
}
///
/// Private formatting method used for optimizing [fmt::Debug] and [fmt::Display] implementations.
///
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "function {}", self.identifier)?;
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
let returns = self.output.to_string();
write!(f, "({}) -> {} {}", parameters, returns, self.block)
}
}
impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
crate::simple_node_impl!(Function);

View File

@ -280,6 +280,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_function(&mut self, input: Function) -> Function {
Function {
annotations: input.annotations,
identifier: input.identifier,
input: input.input,
output: input.output,

View File

@ -30,6 +30,7 @@ impl ParserContext<'_> {
let mut functions = IndexMap::new();
let mut circuits = IndexMap::new();
// TODO: Condense logic
while self.has_next() {
match &self.token.token {
Token::Import => {
@ -40,6 +41,10 @@ impl ParserContext<'_> {
let (id, circuit) = self.parse_circuit()?;
circuits.insert(id, circuit);
}
Token::At => {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
}
Token::Const if self.peek_is_function() => {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
@ -230,6 +235,7 @@ impl ParserContext<'_> {
/// Returns a [`ParamMode`] AST node if the next tokens represent a function parameter mode.
pub(super) fn parse_function_parameter_mode(&mut self) -> Result<ParamMode> {
// TODO: Allow explicit "private" mode.
let public = self.eat(&Token::Public).then(|| self.prev_token.span);
let constant = self.eat(&Token::Constant).then(|| self.prev_token.span);
let const_ = self.eat(&Token::Const).then(|| self.prev_token.span);
@ -241,7 +247,7 @@ impl ParserContext<'_> {
match (public, constant, const_) {
(None, Some(_), None) => Ok(ParamMode::Const),
(None, None, Some(_)) => Ok(ParamMode::Const),
(None, None, None) => Ok(ParamMode::Private),
(None, None, None) => Ok(ParamMode::None),
(Some(_), None, None) => Ok(ParamMode::Public),
(Some(m1), Some(m2), None) | (Some(m1), None, Some(m2)) | (None, Some(m1), Some(m2)) => {
Err(ParserError::inputs_multiple_variable_types_specified(m1 + m2).into())
@ -256,9 +262,7 @@ impl ParserContext<'_> {
fn parse_function_parameter(&mut self) -> Result<FunctionInput> {
let mode = self.parse_function_parameter_mode()?;
let (name, type_) = self.parse_typed_ident()?;
Ok(FunctionInput::Variable(FunctionInputVariable::new(
name, mode, type_, name.span,
)))
Ok(FunctionInput::new(name, mode, type_, name.span))
}
/// Returns `true` if the next token is Function or if it is a Const followed by Function.
@ -270,9 +274,31 @@ impl ParserContext<'_> {
)
}
/// Returns an [`Annotation`] AST node if the next tokens represent an annotation.
fn parse_annotation(&mut self) -> Result<Annotation> {
// Parse the `@` symbol and identifier.
let start = self.expect(&Token::At)?;
let identifier = self.expect_identifier()?;
let span = start + identifier.span;
// TODO: Verify that this check is sound.
// Check that there is no whitespace in between the `@` symbol and identifier.
match identifier.span.hi.0 - start.lo.0 > 1 + identifier.name.to_string().len() as u32 {
true => Err(ParserError::space_in_annotation(span).into()),
false => Ok(Annotation { identifier, span }),
}
}
/// Returns an [`(Identifier, Function)`] AST node if the next tokens represent a function name
/// and function definition.
fn parse_function(&mut self) -> Result<(Identifier, Function)> {
// TODO: Handle dangling annotations.
// TODO: Handle duplicate annotations.
// Parse annotations, if they exist.
let mut annotations = Vec::new();
while self.look_ahead(0, |t| &t.token) == &Token::At {
annotations.push(self.parse_annotation()?)
}
// Parse `function IDENT`.
let start = self.expect(&Token::Function)?;
let name = self.expect_identifier()?;
@ -292,6 +318,7 @@ impl ParserContext<'_> {
Ok((
name,
Function {
annotations,
identifier: name,
input: inputs,
output,

View File

@ -384,6 +384,7 @@ impl Token {
)
}
'^' => return match_two(&mut input, Token::BitXor, '=', Token::BitXorAssign),
'@' => return Ok((1, Token::At)),
_ => (),
}
if let Some(identifier) = eat_identifier(&mut input) {

View File

@ -141,6 +141,7 @@ mod tests {
}}
||
?
@
// test
/* test */
//"#;
@ -153,7 +154,7 @@ mod tests {
assert_eq!(
output,
r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" test_ident 12345 address bool const else false field for function group i128 i64 i32 i16 i8 if in input let mut return scalar string test true u128 u64 u32 u16 u8 console ! != && ( ) * ** + , - -> _ . .. / : ; < <= = == > >= [ ] { { } } || ? // test
r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" test_ident 12345 address bool const else false field for function group i128 i64 i32 i16 i8 if in input let mut return scalar string test true u128 u64 u32 u16 u8 console ! != && ( ) * ** + , - -> _ . .. / : ; < <= = == > >= [ ] { { } } || ? @ // test
/* test */ // "#
);
});

View File

@ -84,6 +84,7 @@ pub enum Token {
Underscore,
BitXor,
BitXorAssign,
At,
// Syntactic Grammar
// Types
@ -281,6 +282,7 @@ impl fmt::Display for Token {
Underscore => write!(f, "_"),
BitXor => write!(f, "^"),
BitXorAssign => write!(f, "^="),
At => write!(f, "@"),
Address => write!(f, "address"),
Bool => write!(f, "bool"),

View File

@ -32,6 +32,9 @@ pub struct CodeGenerator<'a> {
/// The first element of the tuple indicate whether the composite is a record or not.
/// The second element of the tuple is a string modifier used for code generation.
pub(crate) composite_mapping: IndexMap<&'a Symbol, (bool, String)>,
/// Are we traversing a program function?
/// A "program function" is a function that can be invoked by a user or another program.
pub(crate) is_program_function: bool,
}
impl<'a> CodeGenerator<'a> {
@ -43,6 +46,7 @@ impl<'a> CodeGenerator<'a> {
current_function: None,
variable_mapping: IndexMap::new(),
composite_mapping: IndexMap::new(),
is_program_function: false,
}
}
}

View File

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

View File

@ -20,6 +20,7 @@ use leo_ast::{Circuit, CircuitMember, Function, Identifier, Program};
use indexmap::IndexMap;
use itertools::Itertools;
use leo_span::sym;
use std::fmt::Write as _;
impl<'a> CodeGenerator<'a> {
@ -60,14 +61,37 @@ impl<'a> CodeGenerator<'a> {
// Newline separator.
program_string.push('\n');
// Visit each `Function` in the Leo AST and produce a Aleo function instruction.
program_string.push_str(
&input
.functions
.values()
.map(|function| self.visit_function(function))
.join("\n"),
);
// Store closures and functions in separate strings.
let mut closures = String::new();
let mut functions = String::new();
// Visit each `Function` in the Leo AST and produce Aleo instructions.
input.functions.values().for_each(|function| {
// If the function is annotated with `@program`, then it is a program function.
for annotation in function.annotations.iter() {
if annotation.identifier.name == sym::program {
self.is_program_function = true;
}
}
let function_string = self.visit_function(function);
if self.is_program_function {
functions.push_str(&function_string);
functions.push('\n');
} else {
closures.push_str(&function_string);
closures.push('\n');
}
// Unset the `is_program_function` flag.
self.is_program_function = false;
});
// Closures must precede functions in the Aleo program.
program_string.push_str(&closures);
program_string.push('\n');
program_string.push_str(&functions);
program_string
}
@ -140,7 +164,11 @@ impl<'a> CodeGenerator<'a> {
self.current_function = Some(function);
// Construct the header of the function.
let mut function_string = format!("function {}:\n", function.identifier);
// If a function is a program function, generate an Aleo `function`, otherwise generate an Aleo `closure`.
let mut function_string = match self.is_program_function {
true => format!("function {}:\n", function.identifier),
false => format!("closure {}:\n", function.identifier),
};
// Construct and append the input declarations of the function.
for input in function.input.iter() {
@ -148,10 +176,9 @@ impl<'a> CodeGenerator<'a> {
self.next_register += 1;
self.variable_mapping
.insert(&input.get_variable().identifier.name, register_string.clone());
.insert(&input.identifier.name, register_string.clone());
let type_string =
self.visit_type_with_visibility(&input.get_variable().type_, Some(input.get_variable().mode()));
let type_string = self.visit_type_with_visibility(&input.type_, input.mode());
writeln!(function_string, " input {} as {};", register_string, type_string,)
.expect("failed to write to string");
}

View File

@ -18,7 +18,7 @@ use crate::CodeGenerator;
use leo_ast::{
AssignStatement, Block, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression,
IterationStatement, ReturnStatement, Statement,
IterationStatement, ParamMode, ReturnStatement, Statement,
};
use itertools::Itertools;
@ -38,8 +38,8 @@ impl<'a> CodeGenerator<'a> {
fn visit_return(&mut self, input: &'a ReturnStatement) -> String {
let (operand, mut expression_instructions) = self.visit_expression(&input.expression);
let types = self.visit_return_type(&self.current_function.unwrap().output, None);
// TODO: Bytecode functions have an associated output mode. Currently defaulting to private since we do not yet support this at the Leo level.
let types = self.visit_return_type(&self.current_function.unwrap().output, ParamMode::Private);
let mut instructions = operand
.split('\n')
.into_iter()

View File

@ -52,22 +52,29 @@ impl<'a> CodeGenerator<'a> {
}
}
pub(crate) fn visit_type_with_visibility(&mut self, input: &'a Type, visibility: Option<ParamMode>) -> String {
pub(crate) fn visit_type_with_visibility(&mut self, input: &'a Type, visibility: ParamMode) -> String {
let mut type_string = self.visit_type(input);
if let Type::Identifier(_) = input {
// Do not append anything for record and circuit types.
} else {
// Append `.private` to return type.
// todo: CAUTION private by default.
write!(type_string, ".{}", visibility.unwrap_or(ParamMode::Private)).expect("failed to write to string");
// Only program functions need a visibility associated with the input type.
if self.is_program_function {
// If a visibility is not provided in a program function, then it is private by default.
let visibility = match visibility {
ParamMode::None => ParamMode::Private,
_ => visibility,
};
write!(type_string, ".{}", visibility).expect("failed to write to string");
}
}
type_string
}
/// Returns one or more types equal to the number of return tuple members.
pub(crate) fn visit_return_type(&mut self, input: &'a Type, visibility: Option<ParamMode>) -> Vec<String> {
pub(crate) fn visit_return_type(&mut self, input: &'a Type, visibility: ParamMode) -> Vec<String> {
// Handle return tuples.
if let Type::Tuple(types) = input {
types

View File

@ -34,6 +34,7 @@ impl ProgramReconstructor for Unroller<'_> {
// Reconstruct the function block.
let reconstructed_function = Function {
annotations: function.annotations,
identifier: function.identifier,
input: function.input,
output: function.output,

View File

@ -18,8 +18,8 @@ use crate::StaticSingleAssigner;
use itertools::Itertools;
use leo_ast::{
Expression, Function, FunctionInput, ProgramReconstructor, ReturnStatement, Statement, StatementReconstructor,
TernaryExpression, TupleExpression,
Expression, Function, ProgramReconstructor, ReturnStatement, Statement, StatementReconstructor, TernaryExpression,
TupleExpression,
};
impl ProgramReconstructor for StaticSingleAssigner<'_> {
@ -30,15 +30,9 @@ impl ProgramReconstructor for StaticSingleAssigner<'_> {
// There is no need to reconstruct `function.inputs`.
// However, for each input, we must add each symbol to the rename table.
for input in function.input.iter() {
match input {
FunctionInput::Variable(function_input_variable) => {
self.rename_table.update(
function_input_variable.identifier.name,
function_input_variable.identifier.name,
);
}
}
for input_variable in function.input.iter() {
self.rename_table
.update(input_variable.identifier.name, input_variable.identifier.name);
}
let mut block = self.reconstruct_block(function.block);
@ -98,6 +92,7 @@ impl ProgramReconstructor for StaticSingleAssigner<'_> {
self.pop();
Function {
annotations: function.annotations,
identifier: function.identifier,
input: function.input,
output: function.output,

View File

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

View File

@ -26,6 +26,15 @@ use std::collections::HashSet;
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
fn visit_function(&mut self, input: &'a Function) {
// Check that the function's annotations are valid.
for annotation in input.annotations.iter() {
match annotation.identifier.name {
// Set `is_program_function` to true if the corresponding annotation is found.
sym::program => self.is_program_function = true,
_ => self.emit_err(TypeCheckerError::unknown_annotation(annotation, annotation.span)),
}
}
let prev_st = std::mem::take(&mut self.symbol_table);
self.symbol_table
.swap(prev_st.borrow().lookup_fn_scope(input.name()).unwrap());
@ -33,10 +42,16 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
self.has_return = false;
self.parent = Some(input.name());
input.input.iter().for_each(|i| {
let input_var = i.get_variable();
input.input.iter().for_each(|input_var| {
self.assert_not_tuple(input_var.span, &input_var.type_);
// If the function is not a program function, then check that the parameters do not have an associated mode.
if !self.is_program_function && input_var.mode() != ParamMode::None {
self.emit_err(TypeCheckerError::helper_function_inputs_cannot_have_modes(
input_var.span,
));
}
// Check for conflicting variable names.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
input_var.identifier.name,
@ -65,6 +80,9 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
self.symbol_table.swap(prev_st.lookup_fn_scope(input.name()).unwrap());
self.symbol_table = RefCell::new(prev_st);
// Unset `is_program_function` flag.
self.is_program_function = false;
}
fn visit_circuit(&mut self, input: &'a Circuit) {

View File

@ -30,6 +30,9 @@ pub struct TypeChecker<'a> {
pub(crate) parent: Option<Symbol>,
pub(crate) has_return: bool,
pub(crate) negate: bool,
/// Are we traversing a program function?
/// A "program function" is a function that can be invoked by a user or another program.
pub(crate) is_program_function: bool,
}
const BOOLEAN_TYPE: Type = Type::Boolean;
@ -63,6 +66,7 @@ impl<'a> TypeChecker<'a> {
/// Returns a new type checker given a symbol table and error handler.
pub fn new(symbol_table: SymbolTable, handler: &'a Handler) -> Self {
Self {
is_program_function: false,
symbol_table: RefCell::new(symbol_table),
handler,
parent: None,

View File

@ -216,6 +216,7 @@ symbols! {
owner,
gates,
_nonce,
program,
// input file
registers,

View File

@ -253,4 +253,11 @@ create_messages!(
msg: format!("Invalid import call to non-leo file `{name}`."),
help: Some("Only imports of Leo `.leo` files are currently supported.".to_string()),
}
@formatted
space_in_annotation {
args: (),
msg: "Illegal spacing in the annotation declaration.",
help: Some("Remove whitespace between the `@` symbol and the identifier.".to_string()),
}
);

View File

@ -273,4 +273,19 @@ create_messages!(
msg: format!("Loop body contains a return statement or always returns."),
help: Some("Remove the code in the loop body that always returns.".to_string()),
}
// TODO: Consider emitting a warning instead of an error.
@formatted
unknown_annotation {
args: (annotation: impl Display),
msg: format!("Unknown annotation: `{annotation}`."),
help: Some("Use a valid annotation. The Leo compiler supports: `@program`".to_string()),
}
@formatted
helper_function_inputs_cannot_have_modes {
args: (),
msg: format!("Helper functions cannot have modes associated with their inputs."),
help: Some("Consider removing the mode or adding a `@program` annotation to the function.".to_string()),
}
);

View File

@ -16,6 +16,7 @@
// Note that the implementation below uses tuples instead of arrays.
// The implementation also manually unrolls the loop.
@program
function bubble_sort(
arr0: u32,
arr1: u32,

View File

@ -2,6 +2,7 @@
// Core circuit functions are built-in to the Leo language and call handwritten, optimized circuits in the AVM.
// To call a core circuit function, use the correct capitalized circuit identifier followed by two colons
// and then the function. Example: `Pedersen64::hash()`.
@program
function main(a: field) -> field {
let b: field = BHP256::hash(a);
let c: field = Poseidon2::hash(b);

View File

@ -1,5 +1,7 @@
// This function takes a group coordinate as input `a` and performs several operations which should output the `0group`.
// Note that the operations can be called as associated functions on the `a` variable.
@program
function main(a: group) -> group {
// unary
let e: group = a.double(); // 2a

View File

@ -1,8 +0,0 @@
circuit Foo {
x: u64,
y: u64,
}
function bar(x: u64, y: u64) -> Foo {
return Foo {x, y};
}

View File

@ -2,6 +2,3 @@
[main]
public a: u32 = 1u32;
b: u32 = 2u32; // Input variable `b` is private by default.
[foo]
x: u64 = 5u64;

View File

@ -1,7 +1,5 @@
import foo.leo;
// The 'helloworld' main function.
@program
function main(public a: u32, b: u32) -> u32 {
return a + b;
}

View File

@ -3,6 +3,7 @@
import point.leo;
// The main function.
@program
function main(public a: u32, b: u32) -> u32 {
return a + b;
}

View File

@ -11,6 +11,7 @@ circuit Message {
// The "main" function of this Leo program takes a "Message" circuit type as input.
// To see how to input variable "m" is passed in open up `inputs/message.in`.
@program
function main(m: Message) -> field {
// 1. Define the "Message" type.

View File

@ -1,3 +1,6 @@
// This example demonstrates an example of a minting and transferring a token in Leo.
// The `Token` record datatype.
record Token {
// The token owner.
owner: address,
@ -9,6 +12,7 @@ record Token {
// The `mint` function initializes a new record with the
// to the receiver of tokens in `r1` for the receiver in `r0`.
@program
function mint(owner: address, amount: u64) -> Token {
return Token {
owner: owner,
@ -19,6 +23,7 @@ function mint(owner: address, amount: u64) -> Token {
// The `transfer` function sends the specified number of tokens
// to the receiver from the provided token record.
@program
function transfer(token: Token, to: address, amount: u64) -> (Token, Token) {
// Checks the given token record has sufficient balance.

View File

@ -69,6 +69,7 @@ impl MainFile {
fn template(&self) -> String {
format!(
r#"// The '{}' main function.
@program
function main(public a: u32, b: u32) -> u32 {{
let c: u32 = a + b;
return c;

View File

@ -3,6 +3,7 @@ namespace: Bench
expectation: Pass
*/
@program
function hAgrPJzARlhWKDGNpe () -> i128 {
const NtoD9dCOP8: bool = false;
if 60367u16 < 59376u16 && 291621465261548374864687596926221274642u128 <= 158647603833518715931164380862541000072u128 - 92087114510286551502623665863269979099u128 - 6505284705764791705801152244952567434u128 + 141283471013642106073249086828215491558u128 / 178739495978647499334333189200118397544u128 * 0u128 / 69358574294733597814948265413698301968u128 || 32532971286371518024146524900992744351u128 / 73930302096579937058701857000560614114u128 * 0u128 + 219449183973603283961254860147322285177u128 > 72259425234692696526333349807208361947u128 || 94519913150306783765596349821018468848i128 == -145523637561949662187440225436346186585i128 {
@ -158,6 +159,7 @@ function hAgrPJzARlhWKDGNpe () -> i128 {
return ILtBGr5IWbok66cGZo;
}
@program
function kIebmldut (
constant dS71uQ: i64,
constant Dj87fM: i8,
@ -181,6 +183,7 @@ function kIebmldut (
return dS71uQ;
}
@program
function zfUb (n1uGb8qYUbxVeMc: u8) -> field {
const KGVaawVj_y8MuU: u32 = 3924454878u32;
let Rdg5wrR4uJy2GqrYJL: u64 = 11167188615068932487u64;
@ -228,6 +231,7 @@ function zfUb (n1uGb8qYUbxVeMc: u8) -> field {
return WIRhzmLSHlgn;
}
@program
function ey1Y83xwKF4m (
constant WQQo: i64,
constant JzJ3bWUp5V5umYC8mLb: u16
@ -9118,6 +9122,7 @@ function ey1Y83xwKF4m (
}
}
@program
function WNIRQ5XU (
Sao22ploN2: u16,
UAiLILX: u16,
@ -13276,6 +13281,7 @@ function WNIRQ5XU (
}
}
@program
function yKAI11uAlhAC0MKuVaQH (
constant m3q_thgJckCDtZw5: bool,
constant dtIzYvZXAHLLq10L: u16,
@ -13310,6 +13316,7 @@ function yKAI11uAlhAC0MKuVaQH (
return mO8ojODfy3e;
}
@program
function EFXa_yV (
constant lKpXyYB: i16,
vekEtDz_FKl4w: field,
@ -15001,6 +15008,7 @@ function EFXa_yV (
}
}
@program
function nxMY18LG (
constant rv4FX2AtXtt: i128,
constant MyEqz3: u128,
@ -29496,6 +29504,7 @@ function nxMY18LG (
}
}
@program
function ujkWfQ5r_1Yi (
XcnTSn5: bool,
UIgsv89hNR83neLpzYD: i128,
@ -29530,6 +29539,7 @@ function ujkWfQ5r_1Yi (
return iVzW;
}
@program
function mRhFZzGYWFW3 () -> u16 {
let It967SlNwbUzoY3v4iTL: u8 = 217u8;
It967SlNwbUzoY3v4iTL = It967SlNwbUzoY3v4iTL;
@ -29603,6 +29613,7 @@ function mRhFZzGYWFW3 () -> u16 {
return ooC9znSzVmwewD2KL;
}
@program
function ys4SGkFTY8T8t (
constant VdZ1o3oai2nDE8: field,
constant fCskhvo4Zl155ClaZ: u64,
@ -29623,6 +29634,7 @@ function ys4SGkFTY8T8t (
return fCskhvo4Zl155ClaZ;
}
@program
function h0Eadw (
constant IkNFf7x4G3: u32,
sygZ: u128,
@ -34176,6 +34188,7 @@ function h0Eadw (
return sygZ;
}
@program
function dz88xZBpyG7y9Q9yZS (
constant QDWdZ1P6Uxy: u8,
TxLtm4JHFtIxvMQqdXp: i64,
@ -35481,6 +35494,7 @@ function dz88xZBpyG7y9Q9yZS (
}
}
@program
function WAqDjVpXCNT8mVu () -> u64 {
const g96iIWKOcZyNfysxQae: u16 = 45302u16;
let uayEuyji0EjFEjvUSFY: i128 = hAgrPJzARlhWKDGNpe();
@ -35622,6 +35636,7 @@ function WAqDjVpXCNT8mVu () -> u64 {
return IbtV5ITueWPb6mx9PG;
}
@program
function ed_5yepk9ZH7ESz4EfU (
c7iEW8nfI4pcpTUIkmn: field,
m9g1DEE853bNFWWvV: u32,
@ -44516,6 +44531,7 @@ function ed_5yepk9ZH7ESz4EfU (
}
}
@program
function main (constant QZe9: i128) -> i64 {
if 18788u16 != 61211u16 && 33352u16 >= ujkWfQ5r_1Yi(false, QZe9, 14152i16, QZe9) {
let MYnKyRAZnaEo0Ngls7: u128 = 196095035652207868244240086789795221266u128;

View File

@ -3,6 +3,7 @@ namespace: Bench
expectation: Pass
*/
@program
function main() -> u32 {
const a = 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32;
const b = 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32 + 1u32;

View File

@ -3,199 +3,392 @@ namespace: Bench
expectation: Pass
*/
@program
function main() -> u8 {
return x191(0u32);
}
@program
function x0(val: u8) -> u8 { return val; }
@program
function x1(val: u8) -> u8 { return x0(val); }
@program
function x2(val: u8) -> u8 { return x1(val); }
@program
function x3(val: u8) -> u8 { return x2(val); }
@program
function x4(val: u8) -> u8 { return x3(val); }
@program
function x5(val: u8) -> u8 { return x4(val); }
@program
function x6(val: u8) -> u8 { return x5(val); }
@program
function x7(val: u8) -> u8 { return x6(val); }
@program
function x8(val: u8) -> u8 { return x7(val); }
@program
function x9(val: u8) -> u8 { return x8(val); }
@program
function x10(val: u8) -> u8 { return x9(val); }
@program
function x11(val: u8) -> u8 { return x10(val); }
@program
function x12(val: u8) -> u8 { return x11(val); }
@program
function x13(val: u8) -> u8 { return x12(val); }
@program
function x14(val: u8) -> u8 { return x13(val); }
@program
function x15(val: u8) -> u8 { return x14(val); }
@program
function x16(val: u8) -> u8 { return x15(val); }
@program
function x17(val: u8) -> u8 { return x16(val); }
@program
function x18(val: u8) -> u8 { return x17(val); }
@program
function x19(val: u8) -> u8 { return x18(val); }
@program
function x20(val: u8) -> u8 { return x19(val); }
@program
function x21(val: u8) -> u8 { return x20(val); }
@program
function x22(val: u8) -> u8 { return x21(val); }
@program
function x23(val: u8) -> u8 { return x22(val); }
@program
function x24(val: u8) -> u8 { return x23(val); }
@program
function x25(val: u8) -> u8 { return x24(val); }
@program
function x26(val: u8) -> u8 { return x25(val); }
@program
function x27(val: u8) -> u8 { return x26(val); }
@program
function x28(val: u8) -> u8 { return x27(val); }
@program
function x29(val: u8) -> u8 { return x28(val); }
@program
function x30(val: u8) -> u8 { return x29(val); }
@program
function x31(val: u8) -> u8 { return x30(val); }
@program
function x32(val: u8) -> u8 { return x31(val); }
@program
function x33(val: u8) -> u8 { return x32(val); }
@program
function x34(val: u8) -> u8 { return x33(val); }
@program
function x35(val: u8) -> u8 { return x34(val); }
@program
function x36(val: u8) -> u8 { return x35(val); }
@program
function x37(val: u8) -> u8 { return x36(val); }
@program
function x38(val: u8) -> u8 { return x37(val); }
@program
function x39(val: u8) -> u8 { return x38(val); }
@program
function x40(val: u8) -> u8 { return x39(val); }
@program
function x41(val: u8) -> u8 { return x40(val); }
@program
function x42(val: u8) -> u8 { return x41(val); }
@program
function x43(val: u8) -> u8 { return x42(val); }
@program
function x44(val: u8) -> u8 { return x43(val); }
@program
function x45(val: u8) -> u8 { return x44(val); }
@program
function x46(val: u8) -> u8 { return x45(val); }
@program
function x47(val: u8) -> u8 { return x46(val); }
@program
function x48(val: u8) -> u8 { return x47(val); }
@program
function x49(val: u8) -> u8 { return x48(val); }
@program
function x50(val: u8) -> u8 { return x49(val); }
@program
function x51(val: u8) -> u8 { return x50(val); }
@program
function x52(val: u8) -> u8 { return x51(val); }
@program
function x53(val: u8) -> u8 { return x52(val); }
@program
function x54(val: u8) -> u8 { return x53(val); }
@program
function x55(val: u8) -> u8 { return x54(val); }
@program
function x56(val: u8) -> u8 { return x55(val); }
@program
function x57(val: u8) -> u8 { return x56(val); }
@program
function x58(val: u8) -> u8 { return x57(val); }
@program
function x59(val: u8) -> u8 { return x58(val); }
@program
function x60(val: u8) -> u8 { return x59(val); }
@program
function x61(val: u8) -> u8 { return x60(val); }
@program
function x62(val: u8) -> u8 { return x61(val); }
@program
function x63(val: u8) -> u8 { return x62(val); }
@program
function x64(val: u8) -> u8 { return x63(val); }
@program
function x65(val: u8) -> u8 { return x64(val); }
@program
function x66(val: u8) -> u8 { return x65(val); }
@program
function x67(val: u8) -> u8 { return x66(val); }
@program
function x68(val: u8) -> u8 { return x67(val); }
@program
function x69(val: u8) -> u8 { return x68(val); }
@program
function x70(val: u8) -> u8 { return x69(val); }
@program
function x71(val: u8) -> u8 { return x70(val); }
@program
function x72(val: u8) -> u8 { return x71(val); }
@program
function x73(val: u8) -> u8 { return x72(val); }
@program
function x74(val: u8) -> u8 { return x73(val); }
@program
function x75(val: u8) -> u8 { return x74(val); }
@program
function x76(val: u8) -> u8 { return x75(val); }
@program
function x77(val: u8) -> u8 { return x76(val); }
@program
function x78(val: u8) -> u8 { return x77(val); }
@program
function x79(val: u8) -> u8 { return x78(val); }
@program
function x80(val: u8) -> u8 { return x79(val); }
@program
function x81(val: u8) -> u8 { return x80(val); }
@program
function x82(val: u8) -> u8 { return x81(val); }
@program
function x83(val: u8) -> u8 { return x82(val); }
@program
function x84(val: u8) -> u8 { return x83(val); }
@program
function x85(val: u8) -> u8 { return x84(val); }
@program
function x86(val: u8) -> u8 { return x85(val); }
@program
function x87(val: u8) -> u8 { return x86(val); }
@program
function x88(val: u8) -> u8 { return x87(val); }
@program
function x89(val: u8) -> u8 { return x88(val); }
@program
function x90(val: u8) -> u8 { return x89(val); }
@program
function x91(val: u8) -> u8 { return x90(val); }
@program
function x92(val: u8) -> u8 { return x91(val); }
@program
function x93(val: u8) -> u8 { return x92(val); }
@program
function x94(val: u8) -> u8 { return x93(val); }
@program
function x95(val: u8) -> u8 { return x94(val); }
@program
function x96(val: u8) -> u8 { return x95(val); }
@program
function x97(val: u8) -> u8 { return x96(val); }
@program
function x98(val: u8) -> u8 { return x97(val); }
@program
function x99(val: u8) -> u8 { return x98(val); }
@program
function x100(val: u8) -> u8 { return x99(val); }
@program
function x101(val: u8) -> u8 { return x100(val); }
@program
function x102(val: u8) -> u8 { return x101(val); }
@program
function x103(val: u8) -> u8 { return x102(val); }
@program
function x104(val: u8) -> u8 { return x103(val); }
@program
function x105(val: u8) -> u8 { return x104(val); }
@program
function x106(val: u8) -> u8 { return x105(val); }
@program
function x107(val: u8) -> u8 { return x106(val); }
@program
function x108(val: u8) -> u8 { return x107(val); }
@program
function x109(val: u8) -> u8 { return x108(val); }
@program
function x110(val: u8) -> u8 { return x109(val); }
@program
function x111(val: u8) -> u8 { return x110(val); }
@program
function x112(val: u8) -> u8 { return x111(val); }
@program
function x113(val: u8) -> u8 { return x112(val); }
@program
function x114(val: u8) -> u8 { return x113(val); }
@program
function x115(val: u8) -> u8 { return x114(val); }
@program
function x116(val: u8) -> u8 { return x115(val); }
@program
function x117(val: u8) -> u8 { return x116(val); }
@program
function x118(val: u8) -> u8 { return x117(val); }
@program
function x119(val: u8) -> u8 { return x118(val); }
@program
function x120(val: u8) -> u8 { return x119(val); }
@program
function x121(val: u8) -> u8 { return x120(val); }
@program
function x122(val: u8) -> u8 { return x121(val); }
@program
function x123(val: u8) -> u8 { return x122(val); }
@program
function x124(val: u8) -> u8 { return x123(val); }
@program
function x125(val: u8) -> u8 { return x124(val); }
@program
function x126(val: u8) -> u8 { return x125(val); }
@program
function x127(val: u8) -> u8 { return x126(val); }
@program
function x128(val: u8) -> u8 { return x127(val); }
@program
function x129(val: u8) -> u8 { return x128(val); }
@program
function x130(val: u8) -> u8 { return x129(val); }
@program
function x131(val: u8) -> u8 { return x130(val); }
@program
function x132(val: u8) -> u8 { return x131(val); }
@program
function x133(val: u8) -> u8 { return x132(val); }
@program
function x134(val: u8) -> u8 { return x133(val); }
@program
function x135(val: u8) -> u8 { return x134(val); }
@program
function x136(val: u8) -> u8 { return x135(val); }
@program
function x137(val: u8) -> u8 { return x136(val); }
@program
function x138(val: u8) -> u8 { return x137(val); }
@program
function x139(val: u8) -> u8 { return x138(val); }
@program
function x140(val: u8) -> u8 { return x139(val); }
@program
function x141(val: u8) -> u8 { return x140(val); }
@program
function x142(val: u8) -> u8 { return x141(val); }
@program
function x143(val: u8) -> u8 { return x142(val); }
@program
function x144(val: u8) -> u8 { return x143(val); }
@program
function x145(val: u8) -> u8 { return x144(val); }
@program
function x146(val: u8) -> u8 { return x145(val); }
@program
function x147(val: u8) -> u8 { return x146(val); }
@program
function x148(val: u8) -> u8 { return x147(val); }
@program
function x149(val: u8) -> u8 { return x148(val); }
@program
function x150(val: u8) -> u8 { return x149(val); }
@program
function x151(val: u8) -> u8 { return x150(val); }
@program
function x152(val: u8) -> u8 { return x151(val); }
@program
function x153(val: u8) -> u8 { return x152(val); }
@program
function x154(val: u8) -> u8 { return x153(val); }
@program
function x155(val: u8) -> u8 { return x154(val); }
@program
function x156(val: u8) -> u8 { return x155(val); }
@program
function x157(val: u8) -> u8 { return x156(val); }
@program
function x158(val: u8) -> u8 { return x157(val); }
@program
function x159(val: u8) -> u8 { return x158(val); }
@program
function x160(val: u8) -> u8 { return x159(val); }
@program
function x161(val: u8) -> u8 { return x160(val); }
@program
function x162(val: u8) -> u8 { return x161(val); }
@program
function x163(val: u8) -> u8 { return x162(val); }
@program
function x164(val: u8) -> u8 { return x163(val); }
@program
function x165(val: u8) -> u8 { return x164(val); }
@program
function x166(val: u8) -> u8 { return x165(val); }
@program
function x167(val: u8) -> u8 { return x166(val); }
@program
function x168(val: u8) -> u8 { return x167(val); }
@program
function x169(val: u8) -> u8 { return x168(val); }
@program
function x170(val: u8) -> u8 { return x169(val); }
@program
function x171(val: u8) -> u8 { return x170(val); }
@program
function x172(val: u8) -> u8 { return x171(val); }
@program
function x173(val: u8) -> u8 { return x172(val); }
@program
function x174(val: u8) -> u8 { return x173(val); }
@program
function x175(val: u8) -> u8 { return x174(val); }
@program
function x176(val: u8) -> u8 { return x175(val); }
@program
function x177(val: u8) -> u8 { return x176(val); }
@program
function x178(val: u8) -> u8 { return x177(val); }
@program
function x179(val: u8) -> u8 { return x178(val); }
@program
function x180(val: u8) -> u8 { return x179(val); }
@program
function x181(val: u8) -> u8 { return x180(val); }
@program
function x182(val: u8) -> u8 { return x181(val); }
@program
function x183(val: u8) -> u8 { return x182(val); }
@program
function x184(val: u8) -> u8 { return x183(val); }
@program
function x185(val: u8) -> u8 { return x184(val); }
@program
function x186(val: u8) -> u8 { return x185(val); }
@program
function x187(val: u8) -> u8 { return x186(val); }
@program
function x188(val: u8) -> u8 { return x187(val); }
@program
function x189(val: u8) -> u8 { return x188(val); }
@program
function x190(val: u8) -> u8 { return x189(val); }
@program
function x191(val: u8) -> u8 { return x190(val); }

View File

@ -5,6 +5,7 @@ input_file: inputs/address1.in
*/
@program
function main (x: address) -> bool {
let a: address = aleo1fj982yqchhy973kz7e9jk6er7t6qd6jm9anplnlprem507w6lv9spwvfxx;
let b: bool = x.eq(a);

View File

@ -5,6 +5,7 @@ input_file: inputs/branch.in
*/
@program
function main (x: address, y: bool) -> bool {
let z: address = aleo1fj982yqchhy973kz7e9jk6er7t6qd6jm9anplnlprem507w6lv9spwvfxx;
if y {

View File

@ -5,6 +5,7 @@ input_file:
- inputs/address1.in
*/
@program
function main(x: address) -> bool {
const sender: address = aleo10qerras5799u6k7rjtc9y3hcwxuykr45qra7x7dp6jgnc0923czqm0lgta;

View File

@ -6,6 +6,7 @@ input_file:
- inputs/address2.in
*/
@program
function main(x: address) -> bool {
const sender: address = aleo1l7ytv5jqjzpxtjqttl5z9mle8ujcpac9t6tkge5f4haah4pxas8sagzecd;
const receiver: address = aleo1dtpkpg3d653mdlzh6g028937qdgujecn5gw5tzh7ftcvyz7jxvfqw6t8p6;

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
return a && b;
}

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
return a ? b : false;
}

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
return a == b;
}

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
return a != b;
}

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
// unary
let h: bool = a.not();

View File

@ -8,6 +8,7 @@ input_file:
- inputs/true_true.in
*/
@program
function main(a: bool, b: bool) -> bool {
return a || b;
}

View File

@ -14,6 +14,7 @@ circuit Foo {
x: u32
}
@program
function main(x: u32) -> u32 {
let a: Foo = Foo { x: x };
return a.x;

View File

@ -8,6 +8,7 @@ circuit Foo {
x: u32,
}
@program
function main(y: bool) -> bool {
const a: Foo = Foo { x: 1u32 };

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/true.in
*/
@program
function main(a: bool) -> bool {
console.assert(a == true);
return a == true;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(y: bool) -> bool {
console.error("hello error");
return y == true;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(y: bool) -> bool {
console.log("hello world");
return y == true;

View File

@ -7,6 +7,7 @@ input_file:
*/
// Conditionally add two u32 integers and log the result to the console.
@program
function main(a: u32, b: u32) -> bool {
if a == b {
console.log("{}=={}", a, b); // This line should not fail.

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(y: bool) -> bool {
console.log("a = {}", y);
return y == true;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(y: bool) -> bool {
console.log("{}", 1u32);
return y == true;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(y: bool) -> bool {
console.log("{} {}", 1u32, true);
return y == true;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/int64.in
*/
@program
function main(
i8_value: i8,
i16_value: i16,

View File

@ -7,6 +7,7 @@ input_file: inputs/dummy.in
// @test
// function fake_test() {}
@program
function main(y: bool) -> bool {
return y == true;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field, c: field) -> bool {
return a + b == c;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field, c: field) -> bool {
return a / b != c;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field) -> bool {
return a == b;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField + a == 0field;

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field, c: field) -> bool {
return a * b == c;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field) -> bool {
return -a == -b;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field) -> bool {
// unary
let f: field = a.inv();

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField ** 2field == 1field;

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field, c: field) -> bool {
return a - b == c;
}

View File

@ -5,6 +5,7 @@ input_file:
- inputs/fields.in
*/
@program
function main(a: field, b: field, c: field) -> bool {
return b == 1field ? a == 1field : c == 2field;
}

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/integers.in
*/
@program
function main(a: u32) -> u32 {
if a == 2u32 {
return 3u32;

View File

@ -0,0 +1,22 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(a: u32, b: u32, y: bool) -> u32 {
if y {
return adder(a, b);
} else {
return subber(a, b);
}
}
function adder(a: u32, b: u32) -> u32 {
return a + b;
}
function subber(a: u32, b: u32) -> u32 {
return a - b;
}

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/three.in
*/
@program
function main(a: group, b: group, c: group) -> bool {
console.assert(a + b == c);

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/eq.in
*/
@program
function main(a: group, b: group) -> bool {
console.assert(a == b);
return a == b;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/eq.in
*/
@program
function main(a: group, b: group) -> bool {
console.assert(a == b);
return a == b;

View File

@ -5,6 +5,7 @@ input_file:
- inputs/scalar_group.in
*/
@program
function main(a: scalar, b: group, c: scalar) -> bool {
let d: group = 1817767092074430972953743941103352519057913259183777531581123188265134806220group * a;
let e: group = a * 1817767092074430972953743941103352519057913259183777531581123188265134806220group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/dummy.in
*/
@program
function main(a: group, b: group) -> bool {
console.assert(a == b);
return a == b;

View File

@ -5,6 +5,7 @@ input_file:
- inputs/scalar_group.in
*/
@program
function main(a: scalar, b: group) -> group {
return a * b;
}

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/point.in
*/
@program
function main(a: group) -> group {
return 1scalar * a;
}

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/eq.in
*/
@program
function main(a: group, b: group) -> bool {
console.assert(-a == b);

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/three.in
*/
@program
function main(a: group, b: group) -> bool {
// unary
let e: group = a.double();

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/point.in
*/
@program
function main(a: group) -> bool {
return a == (0, 1)group;
}

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/three.in
*/
@program
function main(a: group, b: group, c: group) -> bool {
console.assert(a - b == c);

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/point.in
*/
@program
function main(a: group, b: group, c: group) -> bool {
const r: group = true ? a : b;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/scalar_group.in
*/
@program
function main(a: scalar) -> group {
let b: group = (0, 1)group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/scalar_group.in
*/
@program
function main(a: scalar) -> group {
let b: group = (0, +)group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/scalar_group.in
*/
@program
function main(a: scalar) -> group {
let b: group = (0, _)group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/scalar_group.in
*/
@program
function main(a: scalar) -> group {
let b: group = (0, -)group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/scalar_group.in
*/
@program
function main(a: scalar) -> group {
let element: group = 0group;

View File

@ -4,6 +4,7 @@ expectation: Pass
input_file: inputs/main.in
*/
@program
function main(a: bool) -> bool {
return a == true;
}

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