mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 23:23:50 +03:00
commit
0d0a8a5364
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"**/*.rs": [
|
|
||||||
"// 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/>.",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"ignore": [
|
|
||||||
".cargo",
|
|
||||||
".github",
|
|
||||||
".resources",
|
|
||||||
".travis",
|
|
||||||
"examples",
|
|
||||||
"target/"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -12,4 +12,4 @@
|
|||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
10
build.rs
10
build.rs
@ -57,8 +57,9 @@ fn check_file_licenses<P: AsRef<Path>>(path: P) {
|
|||||||
.read_to_end(&mut contents)
|
.read_to_end(&mut contents)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert_eq!(
|
||||||
contents == EXPECTED_LICENSE_TEXT,
|
contents,
|
||||||
|
EXPECTED_LICENSE_TEXT,
|
||||||
"The license in \"{}\" is either missing or it doesn't match the expected string!",
|
"The license in \"{}\" is either missing or it doesn't match the expected string!",
|
||||||
entry.path().display()
|
entry.path().display()
|
||||||
);
|
);
|
||||||
@ -72,5 +73,8 @@ fn check_file_licenses<P: AsRef<Path>>(path: P) {
|
|||||||
// The build script; it currently only checks the licenses.
|
// The build script; it currently only checks the licenses.
|
||||||
fn main() {
|
fn main() {
|
||||||
// Check licenses in the current folder.
|
// Check licenses in the current folder.
|
||||||
check_file_licenses(".");
|
if !cfg!(target_os = "windows") {
|
||||||
|
// disable license check for windows for now.
|
||||||
|
check_file_licenses(".");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ pub struct Circuit {
|
|||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
/// The fields, constant variables, and functions of this structure.
|
/// The fields, constant variables, and functions of this structure.
|
||||||
pub members: Vec<CircuitMember>,
|
pub members: Vec<CircuitMember>,
|
||||||
|
/// Was this a `record Foo { ... }`?
|
||||||
|
/// If so, it wasn't a circuit.
|
||||||
|
pub is_record: bool,
|
||||||
/// The entire span of the circuit definition.
|
/// The entire span of the circuit definition.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
@ -49,9 +52,18 @@ impl Circuit {
|
|||||||
pub fn name(&self) -> Symbol {
|
pub fn name(&self) -> Symbol {
|
||||||
self.identifier.name
|
self.identifier.name
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
impl fmt::Debug for Circuit {
|
||||||
writeln!(f, "circuit {} {{ ", self.identifier)?;
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
<Self as fmt::Display>::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Circuit {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str(if self.is_record { "record" } else { "circuit" })?;
|
||||||
|
writeln!(f, " {} {{ ", self.identifier)?;
|
||||||
for field in self.members.iter() {
|
for field in self.members.iter() {
|
||||||
writeln!(f, " {}", field)?;
|
writeln!(f, " {}", field)?;
|
||||||
}
|
}
|
||||||
@ -59,16 +71,4 @@ impl Circuit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Circuit {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.format(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Circuit {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.format(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::simple_node_impl!(Circuit);
|
crate::simple_node_impl!(Circuit);
|
||||||
|
@ -57,7 +57,7 @@ pub enum Expression {
|
|||||||
Binary(BinaryExpression),
|
Binary(BinaryExpression),
|
||||||
/// A call expression, e.g., `my_fun(args)`.
|
/// A call expression, e.g., `my_fun(args)`.
|
||||||
Call(CallExpression),
|
Call(CallExpression),
|
||||||
/// An expression constructing a structure like `Foo { bar: 42, baz }`.
|
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
|
||||||
CircuitInit(CircuitInitExpression),
|
CircuitInit(CircuitInitExpression),
|
||||||
/// An expression of type "error".
|
/// An expression of type "error".
|
||||||
/// Will result in a compile error eventually.
|
/// Will result in a compile error eventually.
|
||||||
|
@ -38,18 +38,16 @@ pub struct Program {
|
|||||||
pub circuits: IndexMap<Identifier, Circuit>,
|
pub circuits: IndexMap<Identifier, Circuit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Program> for Program {
|
|
||||||
fn as_ref(&self) -> &Program {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Program {
|
impl fmt::Display for Program {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for (_, function) in self.functions.iter() {
|
for (_, function) in self.functions.iter() {
|
||||||
function.fmt(f)?;
|
function.fmt(f)?;
|
||||||
writeln!(f,)?;
|
writeln!(f,)?;
|
||||||
}
|
}
|
||||||
|
for (_, circuit) in self.circuits.iter() {
|
||||||
|
circuit.fmt(f)?;
|
||||||
|
writeln!(f,)?;
|
||||||
|
}
|
||||||
write!(f, "")
|
write!(f, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,12 +64,12 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the name of the program.
|
/// Extract the name of the program.
|
||||||
pub fn get_name(&self) -> String {
|
pub fn name(&self) -> &str {
|
||||||
self.name.to_string()
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the name of the program.
|
/// Sets the name of the program.
|
||||||
pub fn name(mut self, name: String) -> Self {
|
pub fn set_name(mut self, name: String) -> Self {
|
||||||
self.name = name;
|
self.name = name;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ impl Type {
|
|||||||
| (Type::Scalar, Type::Scalar)
|
| (Type::Scalar, Type::Scalar)
|
||||||
| (Type::String, Type::String) => true,
|
| (Type::String, Type::String) => true,
|
||||||
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
|
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
|
||||||
(Type::Identifier(left), Type::Identifier(right)) => left.eq(right),
|
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use leo_errors::{ParserError, Result};
|
use leo_errors::{ParserError, Result};
|
||||||
use leo_span::sym;
|
|
||||||
|
|
||||||
use snarkvm_dpc::{prelude::Address, testnet2::Testnet2};
|
use snarkvm_dpc::{prelude::Address, testnet2::Testnet2};
|
||||||
|
|
||||||
@ -537,17 +536,8 @@ impl ParserContext<'_> {
|
|||||||
Token::Ident(name) => {
|
Token::Ident(name) => {
|
||||||
let ident = Identifier { name, span };
|
let ident = Identifier { name, span };
|
||||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||||
self.parse_circuit_expression(ident)?
|
// Parse circuit and records inits as circuit expressions.
|
||||||
} else {
|
// Enforce circuit or record type later at type checking.
|
||||||
Expression::Identifier(ident)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Token::SelfUpper => {
|
|
||||||
let ident = Identifier {
|
|
||||||
name: sym::SelfUpper,
|
|
||||||
span,
|
|
||||||
};
|
|
||||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
|
||||||
self.parse_circuit_expression(ident)?
|
self.parse_circuit_expression(ident)?
|
||||||
} else {
|
} else {
|
||||||
Expression::Identifier(ident)
|
Expression::Identifier(ident)
|
||||||
|
@ -27,7 +27,7 @@ impl ParserContext<'_> {
|
|||||||
|
|
||||||
while self.has_next() {
|
while self.has_next() {
|
||||||
match &self.token.token {
|
match &self.token.token {
|
||||||
Token::Circuit => {
|
Token::Circuit | Token::Record => {
|
||||||
let (id, circuit) = self.parse_circuit()?;
|
let (id, circuit) = self.parse_circuit()?;
|
||||||
circuits.insert(id, circuit);
|
circuits.insert(id, circuit);
|
||||||
}
|
}
|
||||||
@ -36,12 +36,10 @@ impl ParserContext<'_> {
|
|||||||
functions.insert(id, function);
|
functions.insert(id, function);
|
||||||
}
|
}
|
||||||
Token::Ident(sym::test) => return Err(ParserError::test_function(self.token.span).into()),
|
Token::Ident(sym::test) => return Err(ParserError::test_function(self.token.span).into()),
|
||||||
// Const functions share the first token with the global Const.
|
|
||||||
Token::Function => {
|
Token::Function => {
|
||||||
let (id, function) = self.parse_function()?;
|
let (id, function) = self.parse_function()?;
|
||||||
functions.insert(id, function);
|
functions.insert(id, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => return Err(Self::unexpected_item(&self.token).into()),
|
_ => return Err(Self::unexpected_item(&self.token).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,9 +63,9 @@ impl ParserContext<'_> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable
|
/// Returns a [`Vec<CircuitMember>`] AST node if the next tokens represent a circuit member variable
|
||||||
/// or circuit member function or circuit member constant.
|
/// or circuit member function or circuit member constant.
|
||||||
pub fn parse_circuit_declaration(&mut self) -> Result<(Vec<CircuitMember>, Span)> {
|
pub fn parse_circuit_members(&mut self) -> Result<(Vec<CircuitMember>, Span)> {
|
||||||
let mut members = Vec::new();
|
let mut members = Vec::new();
|
||||||
|
|
||||||
let (mut semi_colons, mut commas) = (false, false);
|
let (mut semi_colons, mut commas) = (false, false);
|
||||||
@ -106,7 +104,7 @@ impl ParserContext<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `IDENT: TYPE`.
|
/// Parses `IDENT: TYPE`.
|
||||||
fn parse_typed_field_name(&mut self) -> Result<(Identifier, Type)> {
|
fn parse_member(&mut self) -> Result<(Identifier, Type)> {
|
||||||
let name = self.expect_ident()?;
|
let name = self.expect_ident()?;
|
||||||
self.expect(&Token::Colon)?;
|
self.expect(&Token::Colon)?;
|
||||||
let type_ = self.parse_all_types()?.0;
|
let type_ = self.parse_all_types()?.0;
|
||||||
@ -120,7 +118,7 @@ impl ParserContext<'_> {
|
|||||||
self.expect(&Token::Const)?;
|
self.expect(&Token::Const)?;
|
||||||
|
|
||||||
// `IDENT: TYPE = EXPR`:
|
// `IDENT: TYPE = EXPR`:
|
||||||
let (_name, _type_) = self.parse_typed_field_name()?;
|
let (_name, _type_) = self.parse_member()?;
|
||||||
self.expect(&Token::Assign)?;
|
self.expect(&Token::Assign)?;
|
||||||
let expr = self.parse_expression()?;
|
let expr = self.parse_expression()?;
|
||||||
|
|
||||||
@ -134,7 +132,7 @@ impl ParserContext<'_> {
|
|||||||
|
|
||||||
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable.
|
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable.
|
||||||
pub fn parse_member_variable_declaration(&mut self) -> Result<CircuitMember> {
|
pub fn parse_member_variable_declaration(&mut self) -> Result<CircuitMember> {
|
||||||
let (name, type_) = self.parse_typed_field_name()?;
|
let (name, type_) = self.parse_member()?;
|
||||||
|
|
||||||
Ok(CircuitMember::CircuitVariable(name, type_))
|
Ok(CircuitMember::CircuitVariable(name, type_))
|
||||||
}
|
}
|
||||||
@ -145,26 +143,28 @@ impl ParserContext<'_> {
|
|||||||
// CAUTION: function members are unstable for testnet3.
|
// CAUTION: function members are unstable for testnet3.
|
||||||
let function = self.parse_function()?;
|
let function = self.parse_function()?;
|
||||||
|
|
||||||
return Err(ParserError::circuit_functions_unstable(function.1.span()).into());
|
Err(ParserError::circuit_functions_unstable(function.1.span()).into())
|
||||||
// Ok(CircuitMember::CircuitFunction(Box::new(function.1)))
|
// Ok(CircuitMember::CircuitFunction(Box::new(function.1)))
|
||||||
} else {
|
} else {
|
||||||
return Err(Self::unexpected_item(&self.token).into());
|
Err(Self::unexpected_item(&self.token).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`(Identifier, Function)`] ast node if the next tokens represent a circuit declaration.
|
/// Parses a circuit or record definition, e.g., `circit Foo { ... }` or `record Foo { ... }`.
|
||||||
pub(super) fn parse_circuit(&mut self) -> Result<(Identifier, Circuit)> {
|
pub(super) fn parse_circuit(&mut self) -> Result<(Identifier, Circuit)> {
|
||||||
let start = self.expect(&Token::Circuit)?;
|
let is_record = matches!(&self.token.token, Token::Record);
|
||||||
|
let start = self.expect_any(&[Token::Circuit, Token::Record])?;
|
||||||
let circuit_name = self.expect_ident()?;
|
let circuit_name = self.expect_ident()?;
|
||||||
|
|
||||||
self.expect(&Token::LeftCurly)?;
|
self.expect(&Token::LeftCurly)?;
|
||||||
let (members, end) = self.parse_circuit_declaration()?;
|
let (members, end) = self.parse_circuit_members()?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
circuit_name.clone(),
|
circuit_name,
|
||||||
Circuit {
|
Circuit {
|
||||||
identifier: circuit_name,
|
identifier: circuit_name,
|
||||||
members,
|
members,
|
||||||
|
is_record,
|
||||||
span: start + end,
|
span: start + end,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -316,6 +316,7 @@ impl Token {
|
|||||||
"in" => Token::In,
|
"in" => Token::In,
|
||||||
"let" => Token::Let,
|
"let" => Token::Let,
|
||||||
"public" => Token::Public,
|
"public" => Token::Public,
|
||||||
|
"record" => Token::Record,
|
||||||
"return" => Token::Return,
|
"return" => Token::Return,
|
||||||
"scalar" => Token::Scalar,
|
"scalar" => Token::Scalar,
|
||||||
"string" => Token::String,
|
"string" => Token::String,
|
||||||
|
@ -89,7 +89,7 @@ pub enum Token {
|
|||||||
U32,
|
U32,
|
||||||
U64,
|
U64,
|
||||||
U128,
|
U128,
|
||||||
SelfUpper,
|
Record,
|
||||||
|
|
||||||
// Regular Keywords
|
// Regular Keywords
|
||||||
Circuit,
|
Circuit,
|
||||||
@ -140,9 +140,9 @@ pub const KEYWORD_TOKENS: &[Token] = &[
|
|||||||
Token::In,
|
Token::In,
|
||||||
Token::Let,
|
Token::Let,
|
||||||
Token::Public,
|
Token::Public,
|
||||||
|
Token::Record,
|
||||||
Token::Return,
|
Token::Return,
|
||||||
Token::SelfLower,
|
Token::SelfLower,
|
||||||
Token::SelfUpper,
|
|
||||||
Token::Scalar,
|
Token::Scalar,
|
||||||
Token::Static,
|
Token::Static,
|
||||||
Token::String,
|
Token::String,
|
||||||
@ -184,10 +184,10 @@ impl Token {
|
|||||||
Token::In => sym::In,
|
Token::In => sym::In,
|
||||||
Token::Let => sym::Let,
|
Token::Let => sym::Let,
|
||||||
Token::Public => sym::Public,
|
Token::Public => sym::Public,
|
||||||
|
Token::Record => sym::record,
|
||||||
Token::Return => sym::Return,
|
Token::Return => sym::Return,
|
||||||
Token::Scalar => sym::scalar,
|
Token::Scalar => sym::scalar,
|
||||||
Token::SelfLower => sym::SelfLower,
|
Token::SelfLower => sym::SelfLower,
|
||||||
Token::SelfUpper => sym::SelfUpper,
|
|
||||||
Token::Static => sym::Static,
|
Token::Static => sym::Static,
|
||||||
Token::String => sym::string,
|
Token::String => sym::string,
|
||||||
Token::True => sym::True,
|
Token::True => sym::True,
|
||||||
@ -267,7 +267,7 @@ impl fmt::Display for Token {
|
|||||||
U32 => write!(f, "u32"),
|
U32 => write!(f, "u32"),
|
||||||
U64 => write!(f, "u64"),
|
U64 => write!(f, "u64"),
|
||||||
U128 => write!(f, "u128"),
|
U128 => write!(f, "u128"),
|
||||||
SelfUpper => write!(f, "Self"),
|
Record => write!(f, "record"),
|
||||||
|
|
||||||
Circuit => write!(f, "circuit"),
|
Circuit => write!(f, "circuit"),
|
||||||
Console => write!(f, "console"),
|
Console => write!(f, "console"),
|
||||||
|
@ -58,9 +58,14 @@ impl<'a> SymbolTable<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_circuit(&mut self, symbol: Symbol, insert: &'a Circuit) -> Result<()> {
|
pub fn insert_circuit(&mut self, symbol: Symbol, insert: &'a Circuit) -> Result<()> {
|
||||||
if self.circuits.contains_key(&symbol) {
|
if let Some(existing) = self.circuits.get(&symbol) {
|
||||||
// Return an error if the circuit name has already been inserted.
|
// Error if the circuit or record already exists.
|
||||||
return Err(AstError::shadowed_circuit(symbol, insert.span).into());
|
let err = if existing.is_record {
|
||||||
|
AstError::shadowed_record(symbol, insert.span).into()
|
||||||
|
} else {
|
||||||
|
AstError::shadowed_circuit(symbol, insert.span).into()
|
||||||
|
};
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
self.circuits.insert(symbol, insert);
|
self.circuits.insert(symbol, insert);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -99,7 +104,7 @@ impl<'a> SymbolTable<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for SymbolTable<'a> {
|
impl Display for SymbolTable<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "SymbolTable")?;
|
write!(f, "SymbolTable")?;
|
||||||
|
|
||||||
|
@ -528,20 +528,20 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check circuit member types.
|
// Check circuit member types.
|
||||||
circ.members.iter().for_each(|expected| match expected {
|
circ.members
|
||||||
CircuitMember::CircuitVariable(name, type_) => {
|
.iter()
|
||||||
|
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
||||||
// Lookup circuit variable name.
|
// Lookup circuit variable name.
|
||||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
||||||
if let Some(expr) = &actual.expression {
|
if let Some(expr) = &actual.expression {
|
||||||
self.visit_expression(expr, &Some(*type_));
|
self.visit_expression(expr, &Some(*ty));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.handler.emit_err(
|
self.handler.emit_err(
|
||||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
Some(ret)
|
Some(ret)
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,6 +18,7 @@ use crate::{Declaration, TypeChecker, VariableSymbol};
|
|||||||
use leo_ast::*;
|
use leo_ast::*;
|
||||||
use leo_errors::TypeCheckerError;
|
use leo_errors::TypeCheckerError;
|
||||||
|
|
||||||
|
use leo_span::sym;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||||
@ -53,8 +54,32 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
|||||||
// Check for conflicting circuit member names.
|
// Check for conflicting circuit member names.
|
||||||
let mut used = HashSet::new();
|
let mut used = HashSet::new();
|
||||||
if !input.members.iter().all(|member| used.insert(member.name())) {
|
if !input.members.iter().all(|member| used.insert(member.name())) {
|
||||||
self.handler
|
self.handler.emit_err(if input.is_record {
|
||||||
.emit_err(TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into());
|
TypeCheckerError::duplicate_record_variable(input.name(), input.span()).into()
|
||||||
|
} else {
|
||||||
|
TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// For records, enforce presence of `owner: Address` and `balance: u64` members.
|
||||||
|
if input.is_record {
|
||||||
|
let check_has_field = |need, expected_ty: Type| match input
|
||||||
|
.members
|
||||||
|
.iter()
|
||||||
|
.find_map(|CircuitMember::CircuitVariable(v, t)| (v.name == need).then(|| (v, t)))
|
||||||
|
{
|
||||||
|
Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type!
|
||||||
|
Some((field, _)) => {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()).into());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::required_record_variable(need, expected_ty, input.span()).into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
check_has_field(sym::owner, Type::Address);
|
||||||
|
check_has_field(sym::balance, Type::IntegerType(IntegerType::U64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,12 +103,16 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a type checker error.
|
||||||
|
pub(crate) fn emit_err(&self, err: TypeCheckerError) {
|
||||||
|
self.handler.emit_err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
/// Emits an error if the given type conflicts with a core library type.
|
/// Emits an error if the given type conflicts with a core library type.
|
||||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||||
if let Some(Type::Identifier(ident)) = type_ {
|
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
|
self.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()));
|
||||||
.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,9 +125,11 @@ impl<'a> TypeChecker<'a> {
|
|||||||
match CoreInstruction::from_symbols(ident.name, function.name) {
|
match CoreInstruction::from_symbols(ident.name, function.name) {
|
||||||
None => {
|
None => {
|
||||||
// Not a core library circuit.
|
// Not a core library circuit.
|
||||||
self.handler.emit_err(
|
self.emit_err(TypeCheckerError::invalid_core_instruction(
|
||||||
TypeCheckerError::invalid_core_instruction(&ident.name, function.name, ident.span()).into(),
|
&ident.name,
|
||||||
);
|
function.name,
|
||||||
|
ident.span(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Some(core_circuit) => return Some(core_circuit),
|
Some(core_circuit) => return Some(core_circuit),
|
||||||
}
|
}
|
||||||
@ -134,12 +140,10 @@ impl<'a> TypeChecker<'a> {
|
|||||||
/// Emits an error if the two given types are not equal.
|
/// Emits an error if the two given types are not equal.
|
||||||
pub(crate) fn assert_eq_types(&self, t1: Option<Type>, t2: Option<Type>, span: Span) {
|
pub(crate) fn assert_eq_types(&self, t1: Option<Type>, t2: Option<Type>, span: Span) {
|
||||||
match (t1, t2) {
|
match (t1, t2) {
|
||||||
(Some(t1), Some(t2)) if t1 != t2 => self
|
(Some(t1), Some(t2)) if t1 != t2 => self.emit_err(TypeCheckerError::type_should_be(t1, t2, span)),
|
||||||
.handler
|
(Some(type_), None) | (None, Some(type_)) => {
|
||||||
.emit_err(TypeCheckerError::type_should_be(t1, t2, span).into()),
|
self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
|
||||||
(Some(type_), None) | (None, Some(type_)) => self
|
}
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::type_should_be("no type", type_, span).into()),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,9 +151,8 @@ impl<'a> TypeChecker<'a> {
|
|||||||
/// Returns the `circuit` type and emits an error if the `expected` type does not match.
|
/// 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<Type>, span: Span) -> Type {
|
pub(crate) fn assert_expected_circuit(&mut self, circuit: Identifier, expected: &Option<Type>, span: Span) -> Type {
|
||||||
if let Some(Type::Identifier(expected)) = expected {
|
if let Some(Type::Identifier(expected)) = expected {
|
||||||
if expected.name != circuit.name {
|
if !circuit.matches(expected) {
|
||||||
self.handler
|
self.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span));
|
||||||
.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +162,8 @@ impl<'a> TypeChecker<'a> {
|
|||||||
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
|
/// 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<Type>, span: Span) -> Type {
|
pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||||
if let Some(expected) = expected {
|
if let Some(expected) = expected {
|
||||||
if &actual != expected {
|
if !actual.eq_flat(expected) {
|
||||||
self.handler
|
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +174,8 @@ impl<'a> TypeChecker<'a> {
|
|||||||
/// `span` should be the location of the expected type.
|
/// `span` should be the location of the expected type.
|
||||||
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
|
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
|
||||||
if let Some(actual) = actual {
|
if let Some(actual) = actual {
|
||||||
if actual != &expected {
|
if !actual.eq_flat(&expected) {
|
||||||
self.handler
|
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,14 +186,11 @@ impl<'a> TypeChecker<'a> {
|
|||||||
pub(crate) fn assert_one_of_types(&self, type_: &Option<Type>, expected: &[Type], span: Span) {
|
pub(crate) fn assert_one_of_types(&self, type_: &Option<Type>, expected: &[Type], span: Span) {
|
||||||
if let Some(type_) = type_ {
|
if let Some(type_) = type_ {
|
||||||
if !expected.iter().any(|t: &Type| t == type_) {
|
if !expected.iter().any(|t: &Type| t == type_) {
|
||||||
self.handler.emit_err(
|
self.emit_err(TypeCheckerError::expected_one_type_of(
|
||||||
TypeCheckerError::expected_one_type_of(
|
expected.iter().map(|t| t.to_string() + ",").collect::<String>(),
|
||||||
expected.iter().map(|t| t.to_string() + ",").collect::<String>(),
|
type_,
|
||||||
type_,
|
span,
|
||||||
span,
|
));
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,7 @@ keyword = %s"address"
|
|||||||
/ %s"in"
|
/ %s"in"
|
||||||
/ %s"let"
|
/ %s"let"
|
||||||
/ %s"public"
|
/ %s"public"
|
||||||
|
/ %s"record"
|
||||||
/ %s"return"
|
/ %s"return"
|
||||||
/ %s"scalar"
|
/ %s"scalar"
|
||||||
/ %s"string"
|
/ %s"string"
|
||||||
@ -395,8 +396,13 @@ circuit-declaration = %s"circuit" "{" circuit-component-declaration
|
|||||||
|
|
||||||
circuit-component-declaration = identifier ":" type
|
circuit-component-declaration = identifier ":" type
|
||||||
|
|
||||||
|
record-declaration = %s"record" "{" circuit-component-declaration
|
||||||
|
*( "," circuit-component-declaration )
|
||||||
|
[ "," ] "}"
|
||||||
|
|
||||||
declaration = function-declaration
|
declaration = function-declaration
|
||||||
/ circuit-declaration
|
/ circuit-declaration
|
||||||
|
/ record-declaration
|
||||||
|
|
||||||
file = *declaration
|
file = *declaration
|
||||||
|
|
||||||
|
@ -1,8 +1,23 @@
|
|||||||
circuit Foo {
|
record Token {
|
||||||
x: u8,
|
// The token owner.
|
||||||
y: u8,
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
function main(a: u8) -> field {
|
function mint(owner: address, amount: u64) -> Token {
|
||||||
return BHP256::hash(a);
|
return Token {
|
||||||
|
owner,
|
||||||
|
balance: 0u64,
|
||||||
|
amount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(x: address) -> u64 {
|
||||||
|
const c: u64 = 1u64;
|
||||||
|
let t: Token = mint(x, c);
|
||||||
|
|
||||||
|
return t.balance;
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
// CAUTION: Work in progress
|
// CAUTION: Work in progress
|
||||||
|
|
||||||
circuit Token {
|
record Token {
|
||||||
// The token owner.
|
// The token owner.
|
||||||
owner: address,
|
owner: address,
|
||||||
// The Aleo balance (in gates).
|
// The Aleo balance (in gates).
|
||||||
@ -42,7 +42,7 @@ function transfer(r0: Token, r1: Receiver) -> Token {
|
|||||||
let r4: Token = mint(r0.owner, r0.amount);
|
let r4: Token = mint(r0.owner, r0.amount);
|
||||||
|
|
||||||
// return (r3, r4);
|
// return (r3, r4);
|
||||||
return r3
|
return r3;
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() -> u8 {
|
function main() -> u8 {
|
||||||
|
@ -155,6 +155,14 @@ create_messages!(
|
|||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For when a user shadows a record.
|
||||||
|
@formatted
|
||||||
|
shadowed_record {
|
||||||
|
args: (record: impl Display),
|
||||||
|
msg: format!("record `{record}` shadowed by"),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
|
|
||||||
/// For when a user shadows a variable.
|
/// For when a user shadows a variable.
|
||||||
@formatted
|
@formatted
|
||||||
shadowed_variable {
|
shadowed_variable {
|
||||||
|
@ -191,6 +191,16 @@ create_messages!(
|
|||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For when the user tries initialize a circuit with the incorrect number of args.
|
||||||
|
@formatted
|
||||||
|
incorrect_num_record_variables {
|
||||||
|
args: (expected: impl Display, received: impl Display),
|
||||||
|
msg: format!(
|
||||||
|
"Record expected `{expected}` variables, but got `{received}`",
|
||||||
|
),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
|
|
||||||
/// An invalid access call is made e.g., `bool::MAX`
|
/// An invalid access call is made e.g., `bool::MAX`
|
||||||
@formatted
|
@formatted
|
||||||
invalid_access_expression {
|
invalid_access_expression {
|
||||||
@ -211,6 +221,16 @@ create_messages!(
|
|||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempted to define more that one record variable with the same name.
|
||||||
|
@formatted
|
||||||
|
duplicate_record_variable {
|
||||||
|
args: (record: impl Display),
|
||||||
|
msg: format!(
|
||||||
|
"Record {record} defined with more than one variable with the same name."
|
||||||
|
),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempted to access an invalid circuit.
|
/// Attempted to access an invalid circuit.
|
||||||
@formatted
|
@formatted
|
||||||
invalid_circuit {
|
invalid_circuit {
|
||||||
@ -230,4 +250,18 @@ create_messages!(
|
|||||||
),
|
),
|
||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@formatted
|
||||||
|
required_record_variable {
|
||||||
|
args: (name: impl Display, type_: impl Display),
|
||||||
|
msg: format!("The `record` type requires the variable `{name}: {type_}`."),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
@formatted
|
||||||
|
record_var_wrong_type {
|
||||||
|
args: (name: impl Display, type_: impl Display),
|
||||||
|
msg: format!("The field `{name}` in a `record` must have type `{type_}`."),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
// Copyright Rust project developers under MIT or APACHE-2.0.
|
// Copyright Rust project developers under MIT or APACHE-2.0.
|
||||||
|
|
||||||
|
|
||||||
use core::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
use core::cell::{Cell, RefCell};
|
use core::cell::{Cell, RefCell};
|
||||||
use core::mem::{self, MaybeUninit};
|
use core::mem::{self, MaybeUninit};
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
//! Defines the `Span` type used to track where code comes from.
|
//! Defines the `Span` type used to track where code comes from.
|
||||||
|
|
||||||
use core::ops::{Add, Sub};
|
use core::ops::{Add, Sub};
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
use crate::dropless::DroplessArena;
|
use crate::dropless::DroplessArena;
|
||||||
use crate::source_map::SourceMap;
|
use crate::source_map::SourceMap;
|
||||||
|
|
||||||
@ -165,6 +164,7 @@ symbols! {
|
|||||||
i32,
|
i32,
|
||||||
i64,
|
i64,
|
||||||
i128,
|
i128,
|
||||||
|
record,
|
||||||
scalar,
|
scalar,
|
||||||
string,
|
string,
|
||||||
u8,
|
u8,
|
||||||
@ -208,6 +208,12 @@ symbols! {
|
|||||||
test,
|
test,
|
||||||
Type: "type",
|
Type: "type",
|
||||||
|
|
||||||
|
public,
|
||||||
|
private,
|
||||||
|
owner,
|
||||||
|
balance,
|
||||||
|
|
||||||
|
// todo: remove these.
|
||||||
CONTAINER_PSEUDO_CIRCUIT: "$InputContainer",
|
CONTAINER_PSEUDO_CIRCUIT: "$InputContainer",
|
||||||
REGISTERS_PSEUDO_CIRCUIT: "$InputRegister",
|
REGISTERS_PSEUDO_CIRCUIT: "$InputRegister",
|
||||||
RECORD_PSEUDO_CIRCUIT: "$InputRecord",
|
RECORD_PSEUDO_CIRCUIT: "$InputRecord",
|
||||||
@ -216,11 +222,8 @@ symbols! {
|
|||||||
|
|
||||||
// input file
|
// input file
|
||||||
registers,
|
registers,
|
||||||
record,
|
|
||||||
state,
|
state,
|
||||||
state_leaf,
|
state_leaf,
|
||||||
public,
|
|
||||||
private,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interned string.
|
/// An interned string.
|
||||||
|
14
tests/compiler/records/balance_wrong_ty.leo
Normal file
14
tests/compiler/records/balance_wrong_ty.leo
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This record does define the `balance` variable but with the wrong type.
|
||||||
|
record Token {
|
||||||
|
balance: address,
|
||||||
|
owner: address,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
17
tests/compiler/records/declaration.leo
Normal file
17
tests/compiler/records/declaration.leo
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
21
tests/compiler/records/duplicate_circuit_name_fail.leo
Normal file
21
tests/compiler/records/duplicate_circuit_name_fail.leo
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
circuit Token { // This circuit cannot have the same name as the record defined above it.
|
||||||
|
x: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
19
tests/compiler/records/duplicate_var_fail.leo
Normal file
19
tests/compiler/records/duplicate_var_fail.leo
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The token owner.
|
||||||
|
owner: address, // Cannot define two record variables with the same name.
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
28
tests/compiler/records/init_expression.leo
Normal file
28
tests/compiler/records/init_expression.leo
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(r0: address, r1: u64) -> Token {
|
||||||
|
return Token {
|
||||||
|
owner: r0,
|
||||||
|
balance: 0u64,
|
||||||
|
amount: r1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(x: address) -> u64 {
|
||||||
|
const c: u64 = 1u64;
|
||||||
|
let t: Token = mint(x, c);
|
||||||
|
|
||||||
|
return t.balance;
|
||||||
|
}
|
28
tests/compiler/records/init_expression_shorthand.leo
Normal file
28
tests/compiler/records/init_expression_shorthand.leo
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(owner: address, amount: u64) -> Token {
|
||||||
|
return Token {
|
||||||
|
owner,
|
||||||
|
balance: 0u64,
|
||||||
|
amount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(x: address) -> u64 {
|
||||||
|
const c: u64 = 1u64;
|
||||||
|
let t: Token = mint(x, c);
|
||||||
|
|
||||||
|
return t.balance;
|
||||||
|
}
|
28
tests/compiler/records/init_expression_type_fail.leo
Normal file
28
tests/compiler/records/init_expression_type_fail.leo
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(r0: address, r1: u64) -> Token {
|
||||||
|
return Token {
|
||||||
|
owner: r1, // This variable should be type address.
|
||||||
|
balance: 0u64,
|
||||||
|
amount: r0, // This variable should be type u64.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(x: address) -> u64 {
|
||||||
|
const c: u64 = 1u64;
|
||||||
|
let t: Token = mint(x, c);
|
||||||
|
|
||||||
|
return t.balance;
|
||||||
|
}
|
28
tests/compiler/records/init_expression_var_fail.leo
Normal file
28
tests/compiler/records/init_expression_var_fail.leo
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
record Token {
|
||||||
|
// The token owner.
|
||||||
|
owner: address,
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(r0: address, r1: u64) -> Token {
|
||||||
|
return Token {
|
||||||
|
sender: r0, // This variable should be named `owner`.
|
||||||
|
balance: 0u64,
|
||||||
|
amount: r1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(x: address) -> u64 {
|
||||||
|
const c: u64 = 1u64;
|
||||||
|
let t: Token = mint(x, c);
|
||||||
|
|
||||||
|
return t.balance;
|
||||||
|
}
|
0
tests/compiler/records/inputs/address.in
Normal file
0
tests/compiler/records/inputs/address.in
Normal file
16
tests/compiler/records/no_owner_fail.leo
Normal file
16
tests/compiler/records/no_owner_fail.leo
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This record does not define the `owner` variable required for a record type.
|
||||||
|
record Token {
|
||||||
|
// The Aleo balance (in gates).
|
||||||
|
balance: u64,
|
||||||
|
// The token amount.
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
14
tests/compiler/records/owner_wrong_ty.leo
Normal file
14
tests/compiler/records/owner_wrong_ty.leo
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This record does define the `owner` variable but with the wrong type.
|
||||||
|
record Token {
|
||||||
|
balance: u64,
|
||||||
|
owner: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- "Error [ETYC0372018]: Circuit Bar defined with more than one member with the same name.\n --> compiler-test:3:1\n |\n 3 | circuit Bar {\n 4 | x: u32,\n 5 | x: u32,\n 6 | }\n | ^\n"
|
- "Error [ETYC0372019]: Circuit Bar defined with more than one member with the same name.\n --> compiler-test:3:1\n |\n 3 | circuit Bar {\n 4 | x: u32,\n 5 | x: u32,\n 6 | }\n | ^\n"
|
||||||
|
@ -4,5 +4,5 @@ expectation: Pass
|
|||||||
outputs:
|
outputs:
|
||||||
- output:
|
- output:
|
||||||
- initial_input_ast: acb54d555ee391d519919827f5949bf1600d18004ce461097d062f91108563ba
|
- initial_input_ast: acb54d555ee391d519919827f5949bf1600d18004ce461097d062f91108563ba
|
||||||
initial_ast: 347eb4d4a124a759627e26bad6ea283b07b7bc07ab35dc1576faf699c3d91e3d
|
initial_ast: 2fd04130d93c29b06f1288c682dd1ce37731ef0762f8e8d70d994aa97fa55c1e
|
||||||
symbol_table: d522662a21597d6d4b9ca630498b48f40ad05fb289080451879c90c3530de28b
|
symbol_table: d522662a21597d6d4b9ca630498b48f40ad05fb289080451879c90c3530de28b
|
||||||
|
@ -4,5 +4,5 @@ expectation: Pass
|
|||||||
outputs:
|
outputs:
|
||||||
- output:
|
- output:
|
||||||
- initial_input_ast: no input
|
- initial_input_ast: no input
|
||||||
initial_ast: c7a7ae897a82a174983ec9e81f0bcc11328fc55ea24111523131e345a363d9b8
|
initial_ast: 8507cd1753f4d2a835fa34d3d784487d89d595ea415d51145dd7291a839159c2
|
||||||
symbol_table: e6f85704fccd0ca0f0461ae54cb604159a5f41a2175aad6b76bd534166f1bc6b
|
symbol_table: e6f85704fccd0ca0f0461ae54cb604159a5f41a2175aad6b76bd534166f1bc6b
|
||||||
|
@ -4,5 +4,5 @@ expectation: Pass
|
|||||||
outputs:
|
outputs:
|
||||||
- output:
|
- output:
|
||||||
- initial_input_ast: no input
|
- initial_input_ast: no input
|
||||||
initial_ast: 7c16a20b88d661dab8e581d47998252fc0bd2a93199f8b4945c924ade5ebae36
|
initial_ast: 9489ab9b78bd31ac516e1674a83c6b35708238174df88374a7b19cef3d4a8e8a
|
||||||
symbol_table: 9eeb9c327aa691ac9126681fa2d4be149bb69621d30ac30a1432b52e42b56307
|
symbol_table: 9eeb9c327aa691ac9126681fa2d4be149bb69621d30ac30a1432b52e42b56307
|
||||||
|
@ -4,5 +4,5 @@ expectation: Pass
|
|||||||
outputs:
|
outputs:
|
||||||
- output:
|
- output:
|
||||||
- initial_input_ast: 29f6139d908d390f890f04d8ee620757d29b7f71cd48c46ff65bc1e70aae840c
|
- initial_input_ast: 29f6139d908d390f890f04d8ee620757d29b7f71cd48c46ff65bc1e70aae840c
|
||||||
initial_ast: 6e1af09bb13f26f60786c16f66286caffa646eae44511c08c2f6be46d8a1a3d1
|
initial_ast: 630995cc22fb6ec613f02e3aaa18392770158b2bbaf5aa1736c0bf71dd7357ce
|
||||||
symbol_table: 1e3d03c1d2a087812fc00dd4c1b48174df13bc5278fd65c104c9a904644061db
|
symbol_table: 1e3d03c1d2a087812fc00dd4c1b48174df13bc5278fd65c104c9a904644061db
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- "Error [ETYC0372014]: The type Record is a reserved core type name.\n --> compiler-test:4:30\n |\n 4 | function main(public record: Record, a: bool) -> bool {\n | ^^^^^^\n"
|
- "Error [EPAR0370009]: unexpected string: expected 'ident', got 'record'\n --> compiler-test:4:22\n |\n 4 | function main(public record: Record, a: bool) -> bool {\n | ^^^^^^"
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- "Error [EAST0372016]: variable `a` shadowed by\n --> compiler-test:3:23\n |\n 3 | function main(a: u32, a: u32) -> u32 {\n | ^\n"
|
- "Error [EAST0372017]: variable `a` shadowed by\n --> compiler-test:3:23\n |\n 3 | function main(a: u32, a: u32) -> u32 {\n | ^\n"
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372024]: The field `balance` in a `record` must have type `u64`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: address,\n 6 | owner: address,\n 7 | }\n | ^\n"
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
outputs:
|
||||||
|
- output:
|
||||||
|
- initial_input_ast: no input
|
||||||
|
initial_ast: ed6dbb2a60da9a91da4b3845e3919b0520666cf4d7223e5634e1e8e38dd9243d
|
||||||
|
symbol_table: c49906bcded430e36886bfabc35c5740e4657ac82761b80b871f6d19ec6d9dda
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [EAST0372016]: record `Token` shadowed by\n --> compiler-test:12:1\n |\n 12 | circuit Token { // This circuit cannot have the same name as the record defined above it.\n 13 | x: u32,\n 14 | }\n | ^\n"
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372020]: Record Token defined with more than one variable with the same name.\n --> compiler-test:3:1\n |\n 3 | record Token {\n 4 | // The token owner.\n 5 | owner: address,\n 6 | // The token owner.\n 7 | owner: address, // Cannot define two record variables with the same name.\n 8 | // The Aleo balance (in gates).\n 9 | balance: u64,\n 10 | // The token amount.\n 11 | amount: u64,\n 12 | }\n | ^\n"
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
outputs:
|
||||||
|
- output:
|
||||||
|
- initial_input_ast: no input
|
||||||
|
initial_ast: cc9fdc5ee476d5c8930260c5fc50c968915434892180f0084f15cd69b905dc20
|
||||||
|
symbol_table: 926c2f494fbb7914574e7b95bedd8992eaf028143e19bebcdcdf474fcb5eb1c5
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Pass
|
||||||
|
outputs:
|
||||||
|
- output:
|
||||||
|
- initial_input_ast: no input
|
||||||
|
initial_ast: c765de9e29d4ca9bd9ba2f7a5ee72c2e4c8278948d32a6c9a441f5eacde564ea
|
||||||
|
symbol_table: de1844db50840db6655f51a2903da4287d51c03a6e693843bdd6be95c6d627f8
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372003]: Found type `u64` but type `address` was expected\n --> compiler-test:12:28\n |\n 12 | function mint(r0: address, r1: u64) -> Token {\n | ^^\nError [ETYC0372003]: Found type `address` but type `u64` was expected\n --> compiler-test:12:15\n |\n 12 | function mint(r0: address, r1: u64) -> Token {\n | ^^\n"
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372005]: Unknown circuit member variable `owner`\n --> compiler-test:5:5\n |\n 5 | owner: address,\n | ^^^^^\n"
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372023]: The `record` type requires the variable `owner: address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | // The Aleo balance (in gates).\n 6 | balance: u64,\n 7 | // The token amount.\n 8 | amount: u64,\n 9 | }\n | ^\n"
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
outputs:
|
||||||
|
- "Error [ETYC0372024]: The field `owner` in a `record` must have type `address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: u64,\n 6 | owner: bool,\n 7 | }\n | ^\n"
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- "Error [EAST0372016]: variable `x` shadowed by\n --> compiler-test:5:4\n |\n 5 | \tlet x: bool = true;\n | ^^^^^^^^^^^^^^^^^^\n"
|
- "Error [EAST0372017]: variable `x` shadowed by\n --> compiler-test:5:4\n |\n 5 | \tlet x: bool = true;\n | ^^^^^^^^^^^^^^^^^^\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user