diff --git a/compiler/ast/src/expressions/circuit_init.rs b/compiler/ast/src/expressions/circuit_init.rs index 866bbc162b..46e5ad4306 100644 --- a/compiler/ast/src/expressions/circuit_init.rs +++ b/compiler/ast/src/expressions/circuit_init.rs @@ -52,7 +52,7 @@ pub struct CircuitInitExpression { impl fmt::Display for CircuitInitExpression { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {{", self.name)?; + write!(f, "{} {{ ", self.name)?; for member in self.members.iter() { write!(f, "{}", member)?; write!(f, ", ")?; diff --git a/compiler/core/src/algorithms/mod.rs b/compiler/core/src/algorithms/mod.rs index 76f1529256..68447d3b35 100644 --- a/compiler/core/src/algorithms/mod.rs +++ b/compiler/core/src/algorithms/mod.rs @@ -28,21 +28,21 @@ use leo_span::{sym, Symbol}; use indexmap::IndexSet; -/// Returns `true` if the given symbol matches the name of a core circuit. -pub fn is_core_circuit(circuit: Symbol) -> bool { - match circuit { - sym::bhp256 - | sym::bhp512 - | sym::bhp768 - | sym::bhp1024 - | sym::ped64 - | sym::ped128 - | sym::psd2 - | sym::psd4 - | sym::psd8 => true, - _ => false, - } -} +// /// Returns `true` if the given symbol matches the name of a core circuit. +// pub fn is_core_circuit(circuit: Symbol) -> bool { +// match circuit { +// sym::bhp256 +// | sym::bhp512 +// | sym::bhp768 +// | sym::bhp1024 +// | sym::ped64 +// | sym::ped128 +// | sym::psd2 +// | sym::psd4 +// | sym::psd8 => true, +// _ => false, +// } +// } /// A core instruction that maps directly to an AVM bytecode instruction. #[derive(Clone, PartialEq, Eq)] diff --git a/compiler/parser/src/parser/expression.rs b/compiler/parser/src/parser/expression.rs index 7910bed409..84cf262635 100644 --- a/compiler/parser/src/parser/expression.rs +++ b/compiler/parser/src/parser/expression.rs @@ -406,24 +406,26 @@ impl ParserContext<'_> { Some(Ok(gt)) } + fn parse_circuit_member(&mut self) -> Result { + let identifier = self.expect_ident()?; + let expression = if self.eat(&Token::Colon) { + // Parse individual circuit variable declarations. + Some(self.parse_expression()?) + } else { + None + }; + + Ok(CircuitVariableInitializer { identifier, expression }) + } + /// Returns an [`Expression`] AST node if the next tokens represent a /// circuit initialization expression. + /// let foo = Foo { x: 1u8 }; pub fn parse_circuit_expression(&mut self, identifier: Identifier) -> Result { - let (members, _, span) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| { - let expression = if p.eat(&Token::Colon) { - // Parse individual circuit variable declarations. - Some(p.parse_expression()?) - } else { - None - }; + let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_circuit_member().map(Some))?; - Ok(Some(CircuitVariableInitializer { - identifier: p.expect_ident()?, - expression, - })) - })?; Ok(Expression::CircuitInit(CircuitInitExpression { - span: &identifier.span + &span, + span: identifier.span + end, name: identifier, members, })) @@ -480,7 +482,7 @@ impl ParserContext<'_> { Token::StaticString(value) => Expression::Value(ValueExpression::String(value, span)), Token::Ident(name) => { let ident = Identifier { name, span }; - if !self.disallow_circuit_construction && self.eat(&Token::LeftCurly) { + if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) { self.parse_circuit_expression(ident)? } else { Expression::Identifier(ident) @@ -491,7 +493,7 @@ impl ParserContext<'_> { name: sym::SelfUpper, span, }; - if !self.disallow_circuit_construction && self.eat(&Token::LeftCurly) { + if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) { self.parse_circuit_expression(ident)? } else { Expression::Identifier(ident) diff --git a/compiler/parser/src/parser/file.rs b/compiler/parser/src/parser/file.rs index bd4ad58e94..13725059d2 100644 --- a/compiler/parser/src/parser/file.rs +++ b/compiler/parser/src/parser/file.rs @@ -163,8 +163,11 @@ impl ParserContext<'_> { /// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member function. pub fn parse_member_function_declaration(&mut self) -> Result { if self.peek_is_function() { + // CAUTION: function members are unstable for testnet3. let function = self.parse_function()?; - Ok(CircuitMember::CircuitFunction(Box::new(function.1))) + + return Err(ParserError::circuit_functions_unstable(function.1.span()).into()) + // Ok(CircuitMember::CircuitFunction(Box::new(function.1))) } else { return Err(Self::unexpected_item(&self.token).into()); } @@ -246,7 +249,9 @@ impl ParserContext<'_> { // Parse return type. self.expect(&Token::Arrow)?; + self.disallow_circuit_construction = true; let output = self.parse_all_types()?.0; + self.disallow_circuit_construction = false; // Parse the function body. let block = self.parse_block()?; diff --git a/compiler/passes/src/symbol_table/create.rs b/compiler/passes/src/symbol_table/create.rs index 4d2b414a48..c13fc8c0e0 100644 --- a/compiler/passes/src/symbol_table/create.rs +++ b/compiler/passes/src/symbol_table/create.rs @@ -47,4 +47,11 @@ impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> { } VisitResult::SkipChildren } + + fn visit_circuit(&mut self, input: &'a Circuit) -> VisitResult { + if let Err(err) = self.symbol_table.insert_circuit(input.name(), input) { + self.handler.emit_err(err); + } + VisitResult::SkipChildren + } } diff --git a/compiler/passes/src/symbol_table/table.rs b/compiler/passes/src/symbol_table/table.rs index 6d828d76b4..76dea81bbf 100644 --- a/compiler/passes/src/symbol_table/table.rs +++ b/compiler/passes/src/symbol_table/table.rs @@ -16,7 +16,7 @@ use std::fmt::Display; -use leo_ast::Function; +use leo_ast::{Circuit, Function}; use leo_errors::{AstError, Result}; use leo_span::{Span, Symbol}; @@ -26,9 +26,12 @@ use crate::{VariableScope, VariableSymbol}; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct SymbolTable<'a> { - /// Functions represents the name of each function mapped to the Ast's function definition. + /// Maps function names to function definitions. /// This field is populated at a first pass. functions: IndexMap, + /// Maps circuit names to circuit definitions. + /// This field is populated at a first pass. + circuits: IndexMap, /// Variables represents functions variable definitions and input variables. /// This field is not populated till necessary. pub(crate) variables: VariableScope<'a>, @@ -54,6 +57,15 @@ impl<'a> SymbolTable<'a> { Ok(()) } + pub fn insert_circuit(&mut self, symbol: Symbol, insert: &'a Circuit) -> Result<()> { + if self.circuits.contains_key(&symbol) { + // Return an error if the circuit name has already been inserted. + return Err(AstError::shadowed_circuit(symbol, insert.span).into()) + } + self.circuits.insert(symbol, insert); + Ok(()) + } + pub fn insert_variable(&mut self, symbol: Symbol, insert: VariableSymbol<'a>) -> Result<()> { self.check_shadowing(&symbol, insert.span)?; self.variables.variables.insert(symbol, insert); @@ -64,6 +76,10 @@ impl<'a> SymbolTable<'a> { self.functions.get(symbol) } + pub fn lookup_circuit(&self, symbol: &Symbol) -> Option<&&'a Circuit> { + self.circuits.get(symbol) + } + pub fn lookup_variable(&self, symbol: &Symbol) -> Option<&VariableSymbol<'a>> { self.variables.lookup_variable(symbol) } @@ -91,6 +107,10 @@ impl<'a> Display for SymbolTable<'a> { write!(f, "{func}")?; } + for circ in self.circuits.values() { + write!(f, "{circ}")?; + } + write!(f, "{}", self.variables) } } diff --git a/compiler/passes/src/type_checker/check_expressions.rs b/compiler/passes/src/type_checker/check_expressions.rs index fe23210f3c..9773f88244 100644 --- a/compiler/passes/src/type_checker/check_expressions.rs +++ b/compiler/passes/src/type_checker/check_expressions.rs @@ -15,7 +15,6 @@ // along with the Leo library. If not, see . use leo_ast::*; -use leo_core::is_core_circuit; use leo_errors::TypeCheckerError; use crate::TypeChecker; @@ -66,8 +65,8 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> { fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Option { if let VisitResult::VisitChildren = self.visitor.visit_identifier(input) { - return if is_core_circuit(input.name) { - Some(Type::Identifier(*input)) + return if let Some(circuit) = self.visitor.symbol_table.clone().lookup_circuit(&input.name) { + Some(self.visitor.assert_expected_option(Type::Identifier(circuit.identifier.clone()), expected, circuit.span())) } else if let Some(var) = self.visitor.symbol_table.clone().lookup_variable(&input.name) { Some(self.visitor.assert_expected_option(*var.type_, expected, var.span)) } else { @@ -602,9 +601,45 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> { fn visit_circuit_init( &mut self, - _input: &'a CircuitInitExpression, - _additional: &Self::AdditionalInput, + input: &'a CircuitInitExpression, + additional: &Self::AdditionalInput, ) -> Option { - unimplemented!("disable circuit inits for now") + if let Some(circ) = self.visitor.symbol_table.clone().lookup_circuit(&input.name.name) { + // Check circuit type name. + let ret = self.visitor.assert_expected_circuit(circ.identifier, additional, input.name.span()); + + // Check number of circuit members. + if circ.members.len() != input.members.len() { + self.visitor.handler.emit_err( + TypeCheckerError::incorrect_num_circuit_members( + circ.members.len(), + input.members.len(), + input.span(), + ) + .into(), + ); + } + // Check circuit member types + circ.members + .iter() + .zip(input.members.iter()) + .for_each(|(expected, actual)| { + match expected { + CircuitMember::CircuitVariable(_name, type_) => { + if let Some(expr) = &actual.expression { + self.visit_expression(expr, &Some(*type_)); + } + } + _ => {/* Circuit functions cannot be inside circuit init expressions */} + } + }); + + Some(ret) + } else { + self.visitor + .handler + .emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into()); + None + } } } diff --git a/compiler/passes/src/type_checker/check_file.rs b/compiler/passes/src/type_checker/check_file.rs index 601a4bc5f6..02585d07ad 100644 --- a/compiler/passes/src/type_checker/check_file.rs +++ b/compiler/passes/src/type_checker/check_file.rs @@ -53,8 +53,4 @@ impl<'a> ProgramVisitorDirector<'a> for Director<'a> { } } } - - fn visit_circuit(&mut self, _input: &'a Circuit) { - todo!() - } } diff --git a/compiler/passes/src/type_checker/checker.rs b/compiler/passes/src/type_checker/checker.rs index c473f52600..3ef806f0eb 100644 --- a/compiler/passes/src/type_checker/checker.rs +++ b/compiler/passes/src/type_checker/checker.rs @@ -98,9 +98,9 @@ impl<'a> TypeChecker<'a> { /// Emits an error if the given type conflicts with a core library type. pub(crate) fn check_ident_type(&self, type_: &Option) { if let Some(Type::Identifier(ident)) = type_ { - if !(self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name)) { + if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) { self.handler - .emit_err(TypeCheckerError::invalid_core_type(&ident.name, ident.span()).into()); + .emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()).into()); } } } @@ -140,6 +140,18 @@ impl<'a> TypeChecker<'a> { } } + /// Returns the `circuit` type and emits an error if the `expected` type does not match. + pub(crate) fn assert_expected_circuit(&mut self, circuit: Identifier, expected: &Option, span: Span) -> Type { + if let Some(Type::Identifier(expected)) = expected { + if expected.name != circuit.name { + self.handler + .emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span).into()); + } + } + + Type::Identifier(circuit) + } + /// Returns the given `actual` type and emits an error if the `expected` type does not match. pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option, span: Span) -> Type { if let Some(expected) = expected { diff --git a/examples/hello-world/Leo.toml b/examples/hello-world/Leo.toml index 21c9ddd396..74750f2cfc 100644 --- a/examples/hello-world/Leo.toml +++ b/examples/hello-world/Leo.toml @@ -1,6 +1,6 @@ [project] name = "hello-world" -version = "0.2.0" +version = "0.3.0" description = "Logs hello world" license = "LICENSE-MIT" diff --git a/examples/hello-world/src/main.leo b/examples/hello-world/src/main.leo index 619a062417..33952ab765 100644 --- a/examples/hello-world/src/main.leo +++ b/examples/hello-world/src/main.leo @@ -1,3 +1,8 @@ +circuit Foo { + x: u8, + y: u8, +} + function main(a: u8) -> field { - return BHP257::hash(a); + return BHP256::hash(a); } \ No newline at end of file diff --git a/examples/linear-regression/.gitignore b/examples/linear-regression/.gitignore deleted file mode 100644 index 17aa483ab4..0000000000 --- a/examples/linear-regression/.gitignore +++ /dev/null @@ -1 +0,0 @@ -outputs/ diff --git a/examples/linear-regression/Leo.toml b/examples/linear-regression/Leo.toml deleted file mode 100644 index 052350b291..0000000000 --- a/examples/linear-regression/Leo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[project] -name = "linear-regression" -version = "0.1.0" -description = "The linear-regression package" -license = "MIT" - -[remote] -author = "aleo" - -[target] -curve = "bls12_377" -proving_system = "groth16" diff --git a/examples/linear-regression/README.md b/examples/linear-regression/README.md deleted file mode 100644 index 58b8463cbc..0000000000 --- a/examples/linear-regression/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# linear-regression - -## Build Guide - -To compile this Leo program, run: -```bash -leo build -``` - -To test this Leo program, run: -```bash -leo test -``` - -## Development - -To output the number of constraints, run: -```bash -leo build -d -``` diff --git a/examples/linear-regression/inputs/linear-regression.in b/examples/linear-regression/inputs/linear-regression.in deleted file mode 100644 index 2969aa3b83..0000000000 --- a/examples/linear-regression/inputs/linear-regression.in +++ /dev/null @@ -1,7 +0,0 @@ -// The program input for light-cuddly-cyan-polo/src/main.leo -[main] -x: i32 = 1i32; -y: i32 = 2i32; - -[registers] -r0: [i32; 2] = [1i32, 2i32]; diff --git a/examples/linear-regression/inputs/linear-regression.state b/examples/linear-regression/inputs/linear-regression.state deleted file mode 100644 index 3a4a276e17..0000000000 --- a/examples/linear-regression/inputs/linear-regression.state +++ /dev/null @@ -1,26 +0,0 @@ -// The program state for linear-regression/src/main.leo -[[public]] - -[state] -leaf_index: u32 = 0; -root: [u8; 32] = [0; 32]; - -[[private]] - -[record] -serial_number: [u8; 64] = [0; 64]; -commitment: [u8; 32] = [0; 32]; -owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9; -is_dummy: bool = false; -value: u64 = 0; -payload: [u8; 32] = [0; 32]; -birth_program_id: [u8; 48] = [0; 48]; -death_program_id: [u8; 48] = [0; 48]; -serial_number_nonce: [u8; 32] = [0; 32]; -commitment_randomness: [u8; 32] = [0; 32]; - -[state_leaf] -path: [u8; 128] = [0; 128]; -memo: [u8; 32] = [0; 32]; -network_id: u8 = 0; -leaf_randomness: [u8; 32] = [0; 32]; diff --git a/examples/linear-regression/src/main.leo b/examples/linear-regression/src/main.leo deleted file mode 100644 index 51dc4dd908..0000000000 --- a/examples/linear-regression/src/main.leo +++ /dev/null @@ -1,65 +0,0 @@ -circuit Point { - x: i32, - y: i32, - - function new(x: i32, y: i32) -> Self { - return Self { x, y }; - } -} - -circuit LinearRegression { - points: [Point; 5], - - // Instantiates a linear regression circuit. - function new(points: [Point; 5]) -> Self { - return Self { points }; - } - - // Return the slope of the linear regression. - function slope(self) -> i32 { - - let num_points = 5i32; - // Calculate the sums. - let x_sum = 0i32; - let y_sum = 0i32; - let xy_sum = 0i32; - let x2_sum = 0i32; - for i in 0..5 { - x_sum += self.points[i].x; - y_sum += self.points[i].y; - xy_sum += self.points[i].x * self.points[i].y; - x2_sum += self.points[i].x * self.points[i].x; - } - let numerator = (num_points * xy_sum) - (x_sum * y_sum); - let denominator = (num_points * x2_sum) - (x_sum * x_sum); - let slope = numerator / denominator; - return slope; - } - // Return the offset of the linear regression. - function offset(self, slope: i32) -> i32 { - let num_points = 5i32; - // Calculate the sum. - let x_sum = 0i32; - let y_sum = 0i32; - for i in 0..5 { - x_sum += self.points[i].x; - y_sum += self.points[i].y; - } - return (y_sum - slope * x_sum) / num_points; - } -} - - -function main (x: i32, y: i32) -> [i32; 2] { - let points: [Point; 5] = [ - Point{x: x + 1, y: y + 1}, - Point{x: x + 2, y: y + 2}, - Point{x: x + 3, y: y + 3}, - Point{x: x + 4, y: y + 4}, - Point{x: x + 5, y: y + 5} - ]; - let reg = LinearRegression::new(points); - let slope = reg.slope(); - let offset = reg.offset(slope); - return [slope, offset]; -} diff --git a/examples/pedersen-hash/Leo.toml b/examples/pedersen-hash/Leo.toml deleted file mode 100644 index a217cf0127..0000000000 --- a/examples/pedersen-hash/Leo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[project] -name = "pedersen-hash" -version = "0.1.0" -description = "A 256bit hash function" -license = "LICENSE-MIT" - -[remote] -author = "aleo" - -[target] -curve = "bls12_377" -proving_system = "groth16" diff --git a/examples/pedersen-hash/README.md b/examples/pedersen-hash/README.md deleted file mode 100644 index 341d98f707..0000000000 --- a/examples/pedersen-hash/README.md +++ /dev/null @@ -1 +0,0 @@ -# pedersen-hash diff --git a/examples/pedersen-hash/inputs/pedersen-hash.in b/examples/pedersen-hash/inputs/pedersen-hash.in deleted file mode 100644 index 14028c3bf4..0000000000 --- a/examples/pedersen-hash/inputs/pedersen-hash.in +++ /dev/null @@ -1,8 +0,0 @@ -[main] -hash_input: [bool; 256] = [true; 256]; - -[constants] -parameters: [group; 256] = [1group; 256]; - -[registers] -r0: group = (1, 0)group; \ No newline at end of file diff --git a/examples/pedersen-hash/src/main.leo b/examples/pedersen-hash/src/main.leo deleted file mode 100644 index ab6474c4e4..0000000000 --- a/examples/pedersen-hash/src/main.leo +++ /dev/null @@ -1,25 +0,0 @@ -circuit PedersenHash { - parameters: [group; 256]; - - // Instantiates a Pedersen hash circuit - function new(parameters: [group; 256]) -> Self { - return Self { parameters: parameters }; - } - - function hash(self, bits: [bool; 256]) -> group { - let digest: group = 0group; - for i in 0..256 { - if bits[i] { - digest += self.parameters[i]; - } - } - return digest; - } -} - -// The 'pedersen-hash' main function. -function main(hash_input: [bool; 256], const parameters: [group; 256]) -> group { - const pedersen = PedersenHash::new(parameters); - return pedersen.hash(hash_input); -} - diff --git a/examples/silly-sudoku/.gitignore b/examples/silly-sudoku/.gitignore deleted file mode 100644 index ef3a390676..0000000000 --- a/examples/silly-sudoku/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -outputs/ -/.leo diff --git a/examples/silly-sudoku/Leo.toml b/examples/silly-sudoku/Leo.toml deleted file mode 100644 index 386a97dec0..0000000000 --- a/examples/silly-sudoku/Leo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[project] -name = "silly-sudoku" -version = "0.1.3" -description = "A simple Sudoku puzzle grid" -license = "MIT" - -[remote] -author = "howard" - -[target] -curve = "bls12_377" -proving_system = "groth16" diff --git a/examples/silly-sudoku/README.md b/examples/silly-sudoku/README.md deleted file mode 100644 index 59eada079d..0000000000 --- a/examples/silly-sudoku/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# silly-sudoku - -A simple Sudoku puzzle grid in Leo. - -## Walkthrough - -Start by defining a puzzle grid: -``` -[[0, 4, 6], - [3, 0, 9], - [7, 5, 0]] -``` -We treat all 0's as empty cells in the grid. - -Next, generate an answer and construct it as a puzzle grid solution: -``` -[[8, 4, 6], - [3, 1, 9], - [7, 5, 2]] -``` - -The SillySudoku circuit will proceed to verify that the solution grid matches the starting puzzle grid, -and check that each number between 1 - 9 is used exactly once. diff --git a/examples/silly-sudoku/inputs/silly-sudoku.in b/examples/silly-sudoku/inputs/silly-sudoku.in deleted file mode 100644 index 609960e49a..0000000000 --- a/examples/silly-sudoku/inputs/silly-sudoku.in +++ /dev/null @@ -1,12 +0,0 @@ -// The program input for tmp-test/src/main.leo -[main] -puzzle: [u8; (3, 3)] = [[0, 2, 0], - [0, 0, 6], - [0, 8, 9]]; - -answer: [u8; (3, 3)] = [[1, 2, 3], - [4, 5, 6], - [7, 8, 9]]; - -[registers] -r: bool = false; diff --git a/examples/silly-sudoku/inputs/silly-sudoku.state b/examples/silly-sudoku/inputs/silly-sudoku.state deleted file mode 100644 index 440054cd02..0000000000 --- a/examples/silly-sudoku/inputs/silly-sudoku.state +++ /dev/null @@ -1,26 +0,0 @@ -// The program state for tmp-test/src/main.leo -[[public]] - -[state] -leaf_index: u32 = 0; -root: [u8; 32] = [0; 32]; - -[[private]] - -[record] -serial_number: [u8; 64] = [0; 64]; -commitment: [u8; 32] = [0; 32]; -owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9; -is_dummy: bool = false; -value: u64 = 0; -payload: [u8; 32] = [0; 32]; -birth_program_id: [u8; 48] = [0; 48]; -death_program_id: [u8; 48] = [0; 48]; -serial_number_nonce: [u8; 32] = [0; 32]; -commitment_randomness: [u8; 32] = [0; 32]; - -[state_leaf] -path: [u8; 128] = [0; 128]; -memo: [u8; 32] = [0; 32]; -network_id: u8 = 0; -leaf_randomness: [u8; 32] = [0; 32]; diff --git a/examples/silly-sudoku/inputs/test-input.in b/examples/silly-sudoku/inputs/test-input.in deleted file mode 100644 index 36f8362978..0000000000 --- a/examples/silly-sudoku/inputs/test-input.in +++ /dev/null @@ -1,14 +0,0 @@ -// The program input for tmp-test/src/main.leo -[main] -puzzle: [u8; (3, 3)] = [[1, 0, 5], - [0, 2, 0], - [7, 0, 0]]; - -answer: [u8; (3, 3)] = [[1, 4, 5], - [3, 2, 6], - [7, 8, 9]]; - -expected: bool = true; - -[registers] -r: bool = false; diff --git a/examples/silly-sudoku/src/lib.leo b/examples/silly-sudoku/src/lib.leo deleted file mode 100644 index c005af2934..0000000000 --- a/examples/silly-sudoku/src/lib.leo +++ /dev/null @@ -1,70 +0,0 @@ -/** - * The SillySudoku circuit - * - * This circuit generates a silly Sudoku puzzle, - * by constructing a 3x3 puzzle grid with some preset numbers 1-9, - * and requiring an answer where each number is used exactly once. - * - * ----------- - * | 5 | 8 | 3 | - * |-----------| - * | 2 | 7 | 4 | - * |-----------| - * | 1 | 9 | 6 | - * ----------- - */ -circuit SillySudoku { - // The starting grid values for the Sudoku puzzle. - // Unset cells on the puzzle grid are set to 0. - puzzle_grid: [u8; (3, 3)]; - - /** - * Returns true if a given Sudoku answer is correct. - * - * Verifies a given answer by iterating through the Sudoku puzzle, - * and checking that each number is set exactly once. - */ - function solve(self, answer: [u8; (3, 3)]) -> bool { - // The result boolean is set to true, if the answer is correct. - let result = true; - // An array that tracks the numbers used on the Sudoku grid. - let seen = [false; 9]; - - // Iterate through the Sudoku grid and check each cell. - for i in 0..3 { - for j in 0..3 { - - // Fetch the current cell value for the Sudoku grid. - let grid_value = self.puzzle_grid[i][j]; - - // Fetch the current cell value for the given answer. - let answer_value = answer[i][j]; - - // Set the index by subtracting 1 from the answer value. - let index = answer_value - 1; - - // Check if this number has already been used on the grid. - let already_seen: bool = seen[index]; - - // If this number is already used, the answer is incorrect. - // Sets the result to false. - if already_seen { - result = false; - } - - // If the cell is not empty, and the grid value doesn't match - // the answer value, the answer is incorrect. - // Sets the result to false. - if (grid_value != 0 && grid_value != answer_value) { - result = false; - } - - // Sets the answer value as seen. - seen[index] = true; - } - } - - // Returns true if all numbers 1-9 have been seen exactly once. - return result; - } -} diff --git a/examples/silly-sudoku/src/main.leo b/examples/silly-sudoku/src/main.leo deleted file mode 100644 index 856bd8892a..0000000000 --- a/examples/silly-sudoku/src/main.leo +++ /dev/null @@ -1,71 +0,0 @@ -import lib.SillySudoku; - -// The `silly-sudoku` main function -function main(puzzle: [u8; (3, 3)], answer: [u8; (3, 3)]) -> bool { - console.log("Starting Sudoku solver..."); - console.log("{}", puzzle); - - // Instantiate the Sudoku puzzle. - let sudoku = SillySudoku { puzzle_grid: puzzle }; - - console.log("Checking Sudoku answer..."); - console.log("{}", answer); - - // Evaluate the Sudoku puzzle with the given answer. - let result = sudoku.solve(answer); - - console.log("The answer is {}.", result); - - return result; -} - -// Tests that the `silly-sudoku` circuit outputs true on a correct answer. -@test -function test_solve_pass() { - let puzzle: [u8; (3, 3)] = [[0, 2, 0], - [0, 0, 6], - [0, 8, 9]]; - - let answer: [u8; (3, 3)] = [[1, 2, 3], - [4, 5, 6], - [7, 8, 9]]; - - // Runs the Sudoku checker. - let result = main(puzzle, answer); - - // Expects the result to be true. - console.assert(true == result); -} - -// Tests that the `silly-sudoku` circuit outputs false on an incorrect answer. -@test -function test_solve_fail() { - let puzzle: [u8; (3, 3)] = [[0, 2, 0], - [0, 0, 6], - [0, 8, 0]]; - - let answer: [u8; (3, 3)] = [[1, 2, 3], - [4, 5, 6], - [7, 8, 8]]; // We have an extra `8` in this column! - - // Runs the Sudoku checker. - let result = main(puzzle, answer); - - // Expects the result to be false. - console.assert(false == result); -} - -// Test that the `silly-sudoku` circuit outputs the expected value on a custom test input. -@test(test_input) -function test_solve_with_input( - puzzle: [u8; (3, 3)], - answer: [u8; (3, 3)], - expected: bool -) { - // Runs the Sudoku checker. - let result = main(puzzle, answer); - - console.log("expected {}, got {}", expected, result); - - console.assert(expected == result); -} diff --git a/examples/pedersen-hash/.gitignore b/examples/token/.gitignore similarity index 100% rename from examples/pedersen-hash/.gitignore rename to examples/token/.gitignore diff --git a/examples/token/Leo.toml b/examples/token/Leo.toml new file mode 100644 index 0000000000..7c114b4fd2 --- /dev/null +++ b/examples/token/Leo.toml @@ -0,0 +1,11 @@ +[project] +name = "token" +version = "0.3.0" +description = "A simple token" +license = "LICENSE-MIT" + +[remote] +author = "aleo" + +[target] +proving_system = "marlin" diff --git a/examples/token/inputs/token.in b/examples/token/inputs/token.in new file mode 100644 index 0000000000..03eacdd3ad --- /dev/null +++ b/examples/token/inputs/token.in @@ -0,0 +1,3 @@ +[main] + +[registers] diff --git a/examples/pedersen-hash/inputs/pedersen-hash.state b/examples/token/inputs/token.state similarity index 100% rename from examples/pedersen-hash/inputs/pedersen-hash.state rename to examples/token/inputs/token.state diff --git a/examples/token/src/main.leo b/examples/token/src/main.leo new file mode 100644 index 0000000000..6b52079780 --- /dev/null +++ b/examples/token/src/main.leo @@ -0,0 +1,50 @@ +// CAUTION: Work in progress + +circuit Token { + // The token owner. + owner: address, + // The Aleo balance (in gates). + balance: u64, + // The token amount. + amount: u64, +} + +circuit Receiver { + // The token owner. + owner: Address, + // The token amount. + amount: u64, +} + +function mint(r0: address, r1: u64) -> Token { + return Token { + owner: r0, + balance: 0u64, + amount: r1, + }; +} + +// The `transfer` function sends the specified number of tokens +// to the receiver from the provided token record. +function transfer(r0: Token, r1: Receiver) -> Token { + // Checks the given token record has sufficient balance. + // This `sub` operation is safe, and the proof will fail + // if an overflow occurs. The output register `r2` holds + // the change amount to be returned to the sender. + let r2: u64 = r0.amount - r1.amount; + + // Calls the `mint` function to produce a token record + // for the specified receiver. + let r3: Token = mint(r1.owner, r1.amount); + + // Calls the `mint` function to produce a token record + // with the change amount for the sender. + let r4: Token = mint(r0.owner, r0.amount); + + // return (r3, r4); + return r3 +} + +function main() -> u8 { + return 1u8; +} \ No newline at end of file diff --git a/leo/errors/src/errors/ast/ast_errors.rs b/leo/errors/src/errors/ast/ast_errors.rs index d9d7804f1d..6e751086e8 100644 --- a/leo/errors/src/errors/ast/ast_errors.rs +++ b/leo/errors/src/errors/ast/ast_errors.rs @@ -147,6 +147,14 @@ create_messages!( help: None, } + /// For when a user shadows a circuit. + @formatted + shadowed_circuit { + args: (circ: impl Display), + msg: format!("circuit `{circ}` shadowed by"), + help: None, + } + /// For when a user shadows a variable. @formatted shadowed_variable { diff --git a/leo/errors/src/errors/parser/parser_errors.rs b/leo/errors/src/errors/parser/parser_errors.rs index 1ebf2d67dc..88f284910a 100644 --- a/leo/errors/src/errors/parser/parser_errors.rs +++ b/leo/errors/src/errors/parser/parser_errors.rs @@ -374,4 +374,12 @@ create_messages!( msg: "Arbitrary methods calls are not supported. Only special ones are.", help: None, } + + /// Circuit functions are unstable in testnet3. + @formatted + circuit_functions_unstable { + args: (), + msg: "Circuit functions are currently an unstable feature and are disabled in Leo for testnet3", + help: None, + } ); diff --git a/leo/errors/src/errors/type_checker/type_checker_error.rs b/leo/errors/src/errors/type_checker/type_checker_error.rs index 358f51619f..9a340603dc 100644 --- a/leo/errors/src/errors/type_checker/type_checker_error.rs +++ b/leo/errors/src/errors/type_checker/type_checker_error.rs @@ -153,12 +153,12 @@ create_messages!( help: None, } - /// For when an invalid core type is used. + /// For when a circuit is created with the same name as a core type. @formatted - invalid_core_type { + core_type_name_conflict { args: (type_: impl Display), msg: format!( - "The type {type_} is not a valid core type.", + "The type {type_} is a reserved core type name.", ), help: None, } @@ -172,4 +172,14 @@ create_messages!( ), help: None, } + + /// For when the user tries initialize a circuit with the incorrect number of args. + @formatted + incorrect_num_circuit_members { + args: (expected: impl Display, received: impl Display), + msg: format!( + "Circuit expected `{expected}` members, but got `{received}`", + ), + help: None, + } );