mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 18:21:38 +03:00
Merge branch 'testnet3' into improve-parser-tests
This commit is contained in:
commit
39ea7a3ceb
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -240,9 +240,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.2"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5177fac1ab67102d8989464efd043c6ff44191b1557ec1ddd489b4f7e1447e77"
|
||||
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -250,7 +250,7 @@ dependencies = [
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.14.2",
|
||||
"textwrap 0.15.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1071,7 +1071,7 @@ version = "1.5.3"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"assert_cmd",
|
||||
"clap 3.1.2",
|
||||
"clap 3.1.5",
|
||||
"color-backtrace",
|
||||
"colored",
|
||||
"console",
|
||||
@ -2220,9 +2220,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
|
@ -550,9 +550,7 @@ impl ReconstructingReducer for Canonicalizer {
|
||||
for (index, character) in string.iter().enumerate() {
|
||||
let col_start = span.col_start + index + 1 + col_adder; // account for open quote
|
||||
let bytes = span.content.clone().into_bytes();
|
||||
let col_stop: usize;
|
||||
|
||||
if bytes[col_start - 1] == b'\\' {
|
||||
let col_stop = if bytes[col_start - 1] == b'\\' {
|
||||
let mut width = 0;
|
||||
|
||||
match bytes[col_start] {
|
||||
@ -569,10 +567,10 @@ impl ReconstructingReducer for Canonicalizer {
|
||||
_ => width += 1,
|
||||
}
|
||||
col_adder += width;
|
||||
col_stop = col_start + 1 + width;
|
||||
col_start + 1 + width
|
||||
} else {
|
||||
col_stop = col_start + 1;
|
||||
}
|
||||
col_start + 1
|
||||
};
|
||||
|
||||
elements.push(SpreadOrExpression::Expression(Expression::Value(
|
||||
ValueExpression::Char(CharValue {
|
||||
|
@ -20,45 +20,12 @@ use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::{fmt, ops::Deref};
|
||||
|
||||
/// A single array dimension.
|
||||
#[derive(Clone, Deserialize, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Dimension {
|
||||
/// The dimension is `_`, that is unspecified and syntactically unknown.
|
||||
Unspecified,
|
||||
/// The dimension was specified, e.g., `5` elements.
|
||||
Number(PositiveNumber),
|
||||
}
|
||||
|
||||
impl fmt::Display for Dimension {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Unspecified => write!(f, "_"),
|
||||
Self::Number(num) => write!(f, "{}", num),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dimension {
|
||||
/// } Returns `Some(n)` unless the dimension is [`Unspecified`].
|
||||
pub fn as_specified(&self) -> Option<&PositiveNumber> {
|
||||
match self {
|
||||
Self::Unspecified => None,
|
||||
Self::Number(n) => Some(n),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the dimension is known to be zero.
|
||||
fn is_zero(&self) -> bool {
|
||||
self.as_specified().filter(|n| n.is_zero()).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies array dimensions for array [`Type`]s or in array initializer [`Expression`]s.
|
||||
#[derive(Clone, Deserialize, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ArrayDimensions(pub SmallVec<[Dimension; 1]>);
|
||||
pub struct ArrayDimensions(pub SmallVec<[PositiveNumber; 1]>);
|
||||
|
||||
impl Deref for ArrayDimensions {
|
||||
type Target = [Dimension];
|
||||
type Target = [PositiveNumber];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
@ -67,22 +34,17 @@ impl Deref for ArrayDimensions {
|
||||
|
||||
impl ArrayDimensions {
|
||||
/// Returns a single-dimensional array dimension.
|
||||
pub fn single(dim: Dimension) -> Self {
|
||||
pub fn single(dim: PositiveNumber) -> Self {
|
||||
Self(smallvec![dim])
|
||||
}
|
||||
|
||||
/// Returns true if the dimensions are not [`Unspecified`].
|
||||
pub fn is_specified(&self) -> bool {
|
||||
!self.contains(&Dimension::Unspecified)
|
||||
}
|
||||
|
||||
/// Returns `true` if there is an array dimension equal to zero.
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.iter().any(|d| d.is_zero())
|
||||
}
|
||||
|
||||
/// Attempts to remove the first dimension from the array, or returns `None` if it doesn't.
|
||||
pub fn remove_first(&mut self) -> Option<Dimension> {
|
||||
pub fn remove_first(&mut self) -> Option<PositiveNumber> {
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
@ -91,12 +53,12 @@ impl ArrayDimensions {
|
||||
}
|
||||
|
||||
/// Attempts to remove the last dimension from the array, or returns `None` if it doesn't.
|
||||
pub fn remove_last(&mut self) -> Option<Dimension> {
|
||||
pub fn remove_last(&mut self) -> Option<PositiveNumber> {
|
||||
self.0.pop()
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom Serializer for ArrayDimensios is required to ignore internal ArrayDimension nodes in the AST.
|
||||
/// Custom Serializer for ArrayDimensions is required to ignore internal ArrayDimension nodes in the AST.
|
||||
impl Serialize for ArrayDimensions {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@ -104,10 +66,7 @@ impl Serialize for ArrayDimensions {
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
|
||||
for dim in self.0.iter() {
|
||||
match dim {
|
||||
Dimension::Number(num) => seq.serialize_element(&num)?,
|
||||
Dimension::Unspecified => seq.serialize_element(&PositiveNumber { value: "0".into() })?,
|
||||
}
|
||||
seq.serialize_element(&dim)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
@ -88,32 +88,28 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
}
|
||||
|
||||
if let Some(dimension) = array_init.dimensions.remove_first() {
|
||||
if let Some(number) = dimension.as_specified() {
|
||||
let size = number.value.parse::<usize>().unwrap();
|
||||
let mut values = Vec::with_capacity(size);
|
||||
let size = dimension.value.parse::<usize>().unwrap();
|
||||
let mut values = Vec::with_capacity(size);
|
||||
|
||||
// For when Dimensions are specified in a canonical way: [[u8; 3], 2];
|
||||
// Else treat as math notation: [u8; (2, 3)];
|
||||
if array_init.dimensions.len() == 0 {
|
||||
for _ in 0..size {
|
||||
values.push(InputValue::try_from((*type_.clone(), *array_init.element.clone()))?);
|
||||
}
|
||||
// Faking canonical array init is relatively easy: instead of using a straightforward
|
||||
// recursion, with each iteration we manually modify ArrayInitExpression cutting off
|
||||
// dimension by dimension.
|
||||
} else {
|
||||
for _ in 0..size {
|
||||
values.push(InputValue::try_from((
|
||||
Type::Array(type_.clone(), array_init.dimensions.clone()),
|
||||
Expression::ArrayInit(array_init.clone()),
|
||||
))?);
|
||||
}
|
||||
};
|
||||
|
||||
Self::Array(values)
|
||||
// For when Dimensions are specified in a canonical way: [[u8; 3], 2];
|
||||
// Else treat as math notation: [u8; (2, 3)];
|
||||
if array_init.dimensions.len() == 0 {
|
||||
for _ in 0..size {
|
||||
values.push(InputValue::try_from((*type_.clone(), *array_init.element.clone()))?);
|
||||
}
|
||||
// Faking canonical array init is relatively easy: instead of using a straightforward
|
||||
// recursion, with each iteration we manually modify ArrayInitExpression cutting off
|
||||
// dimension by dimension.
|
||||
} else {
|
||||
unreachable!("dimensions must be specified");
|
||||
}
|
||||
for _ in 0..size {
|
||||
values.push(InputValue::try_from((
|
||||
Type::Array(type_.clone(), array_init.dimensions.clone()),
|
||||
Expression::ArrayInit(array_init.clone()),
|
||||
))?);
|
||||
}
|
||||
};
|
||||
|
||||
Self::Array(values)
|
||||
} else {
|
||||
unreachable!("dimensions are checked for zero");
|
||||
}
|
||||
@ -132,14 +128,10 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
|
||||
Self::Tuple(elements)
|
||||
}
|
||||
(Type::Array(element_type, dimensions), Expression::ArrayInline(array_inline)) => {
|
||||
(Type::Array(element_type, _dimensions), Expression::ArrayInline(array_inline)) => {
|
||||
let mut elements = Vec::with_capacity(array_inline.elements.len());
|
||||
let span = array_inline.span().clone();
|
||||
|
||||
if !dimensions.is_specified() {
|
||||
return Err(InputError::array_dimensions_must_be_specified(&span).into());
|
||||
}
|
||||
|
||||
for element in array_inline.elements.into_iter() {
|
||||
if let SpreadOrExpression::Expression(value_expression) = element {
|
||||
elements.push(Self::try_from((*element_type.clone(), value_expression))?);
|
||||
|
@ -89,11 +89,6 @@ impl Type {
|
||||
let mut left_dims = left_dims.to_owned();
|
||||
let mut right_dims = right_dims.to_owned();
|
||||
|
||||
// Unable to compare arrays with unspecified sizes.
|
||||
if !left_dims.is_specified() || !right_dims.is_specified() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the first element from both dimensions.
|
||||
let left_first = left_dims.remove_first();
|
||||
let right_first = right_dims.remove_first();
|
||||
|
@ -82,7 +82,7 @@ impl<'a> Compiler<'a> {
|
||||
program_string,
|
||||
)?;
|
||||
// Write the AST snapshot post parsing.
|
||||
ast.to_json_file_without_keys(self.output_directory.clone(), "inital_ast.json", &["span"])?;
|
||||
ast.to_json_file_without_keys(self.output_directory.clone(), "initial_ast.json", &["span"])?;
|
||||
|
||||
// Canonicalize the AST.
|
||||
ast = leo_ast_passes::Canonicalizer::do_pass(Default::default(), ast.into_repr())?;
|
||||
|
@ -114,11 +114,9 @@ impl ParserContext<'_> {
|
||||
let (args, _, span) = self.parse_paren_comma_list(|p| {
|
||||
Ok(if let Some(ident) = p.eat_identifier() {
|
||||
Some(ident.name)
|
||||
} else if let Some((int, _)) = p.eat_int() {
|
||||
Some(Symbol::intern(&int.value))
|
||||
} else {
|
||||
let token = p.expect_any()?;
|
||||
p.emit_err(ParserError::unexpected_str(&token.token, "ident or int", &token.span));
|
||||
p.emit_err(ParserError::unexpected_str(&token.token, "ident", &token.span));
|
||||
None
|
||||
})
|
||||
})?;
|
||||
@ -363,7 +361,7 @@ impl ParserContext<'_> {
|
||||
///
|
||||
/// Returns a [`FunctionInput`] AST node if the next tokens represent a function parameter.
|
||||
///
|
||||
pub fn parse_function_parameters(&mut self) -> Result<FunctionInput> {
|
||||
pub fn parse_function_parameters(&mut self, first: bool) -> Result<FunctionInput> {
|
||||
let const_ = self.eat(Token::Const);
|
||||
let mutable = self.eat(Token::Mut);
|
||||
let reference = self.eat(Token::Ampersand);
|
||||
@ -376,7 +374,9 @@ impl ParserContext<'_> {
|
||||
self.expect_ident()?
|
||||
};
|
||||
if name.name == sym::SelfLower {
|
||||
if let Some(mutable) = &mutable {
|
||||
if !first {
|
||||
return Err(ParserError::parser_self_outside_first_argument().into());
|
||||
} else if let Some(mutable) = &mutable {
|
||||
self.emit_err(ParserError::mut_self_parameter(&(&mutable.span + &name.span)));
|
||||
return Ok(Self::build_ref_self(name, mutable));
|
||||
} else if let Some(reference) = &reference {
|
||||
@ -433,7 +433,12 @@ impl ParserContext<'_> {
|
||||
let name = self.expect_ident()?;
|
||||
|
||||
// Parse parameters.
|
||||
let (inputs, ..) = self.parse_paren_comma_list(|p| p.parse_function_parameters().map(Some))?;
|
||||
let mut first = true;
|
||||
let (inputs, ..) = self.parse_paren_comma_list(|p| {
|
||||
let param = p.parse_function_parameters(first).map(Some);
|
||||
first = false;
|
||||
param
|
||||
})?;
|
||||
|
||||
// Parse return type.
|
||||
let output = if self.eat(Token::Arrow).is_some() {
|
||||
|
@ -59,12 +59,12 @@ impl ParserContext<'_> {
|
||||
|
||||
/// Returns an [`ArrayDimensions`] AST node if the next tokens represent dimensions for an array type.
|
||||
pub fn parse_array_dimensions(&mut self) -> Result<ArrayDimensions> {
|
||||
Ok(if let Some(dim) = self.parse_array_dimension() {
|
||||
Ok(if let Some((dim, _)) = self.eat_int() {
|
||||
ArrayDimensions(smallvec![dim])
|
||||
} else {
|
||||
let mut had_item_err = false;
|
||||
let (dims, _, span) = self.parse_paren_comma_list(|p| {
|
||||
Ok(if let Some(dim) = p.parse_array_dimension() {
|
||||
Ok(if let Some((dim, _)) = p.eat_int() {
|
||||
Some(dim)
|
||||
} else {
|
||||
let token = p.expect_any()?;
|
||||
@ -80,17 +80,6 @@ impl ParserContext<'_> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a basic array dimension, i.e., an integer or `_`.
|
||||
fn parse_array_dimension(&mut self) -> Option<Dimension> {
|
||||
if let Some((int, _)) = self.eat_int() {
|
||||
Some(Dimension::Number(int))
|
||||
} else if self.eat(Token::Underscore).is_some() {
|
||||
Some(Dimension::Unspecified)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [`(Type, Span)`] tuple of AST nodes if the next token represents a type.
|
||||
/// Also returns the span of the parsed token.
|
||||
pub fn parse_type(&mut self) -> Result<(Type, Span)> {
|
||||
|
@ -63,9 +63,9 @@ impl Token {
|
||||
///
|
||||
/// Returns a `char` if a character can be eaten, otherwise returns [`None`].
|
||||
///
|
||||
fn eat_char(input_tendril: StrTendril, escaped: bool, hex: bool, unicode: bool) -> Option<Char> {
|
||||
fn eat_char(input_tendril: StrTendril, escaped: bool, hex: bool, unicode: bool) -> Result<Char> {
|
||||
if input_tendril.is_empty() {
|
||||
return None;
|
||||
return Err(ParserError::lexer_empty_input_tendril().into());
|
||||
}
|
||||
|
||||
if escaped {
|
||||
@ -73,19 +73,21 @@ impl Token {
|
||||
let escaped = &string[1..string.len()];
|
||||
|
||||
if escaped.len() != 1 {
|
||||
return None;
|
||||
} else {
|
||||
return match escaped.chars().next().unwrap() {
|
||||
'0' => Some(Char::Scalar(0 as char)),
|
||||
't' => Some(Char::Scalar(9 as char)),
|
||||
'n' => Some(Char::Scalar(10 as char)),
|
||||
'r' => Some(Char::Scalar(13 as char)),
|
||||
'\"' => Some(Char::Scalar(34 as char)),
|
||||
'\'' => Some(Char::Scalar(39 as char)),
|
||||
'\\' => Some(Char::Scalar(92 as char)),
|
||||
_ => None,
|
||||
return Err(ParserError::lexer_escaped_char_incorrect_length(escaped).into());
|
||||
} else if let Some(character) = escaped.chars().next() {
|
||||
return match character {
|
||||
'0' => Ok(Char::Scalar(0 as char)),
|
||||
't' => Ok(Char::Scalar(9 as char)),
|
||||
'n' => Ok(Char::Scalar(10 as char)),
|
||||
'r' => Ok(Char::Scalar(13 as char)),
|
||||
'\"' => Ok(Char::Scalar(34 as char)),
|
||||
'\'' => Ok(Char::Scalar(39 as char)),
|
||||
'\\' => Ok(Char::Scalar(92 as char)),
|
||||
_ => return Err(ParserError::lexer_expected_valid_escaped_char(character).into()),
|
||||
};
|
||||
};
|
||||
} else {
|
||||
return Err(ParserError::lexer_unclosed_escaped_char().into());
|
||||
}
|
||||
}
|
||||
|
||||
if hex {
|
||||
@ -93,46 +95,50 @@ impl Token {
|
||||
let hex_string = &string[2..string.len()];
|
||||
|
||||
if hex_string.len() != 2 {
|
||||
return None;
|
||||
return Err(ParserError::lexer_escaped_hex_incorrect_length(hex_string).into());
|
||||
} else if let Ok(ascii_number) = u8::from_str_radix(hex_string, 16) {
|
||||
// According to RFC, we allow only values less than 128.
|
||||
if ascii_number > 127 {
|
||||
return None;
|
||||
return Err(ParserError::lexer_expected_valid_hex_char(ascii_number).into());
|
||||
} else {
|
||||
return Some(Char::Scalar(ascii_number as char));
|
||||
return Ok(Char::Scalar(ascii_number as char));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if unicode {
|
||||
let string = input_tendril.to_string();
|
||||
if &string[string.len() - 1..] != "}" {
|
||||
return None;
|
||||
if string.find('}').is_none() {
|
||||
return Err(ParserError::lexer_unclosed_escaped_unicode_char(string).into());
|
||||
}
|
||||
|
||||
let unicode_number = &string[3..string.len() - 1];
|
||||
let len = unicode_number.len();
|
||||
if !(1..=6).contains(&len) {
|
||||
return None;
|
||||
return Err(ParserError::lexer_invalid_escaped_unicode_length(unicode_number).into());
|
||||
} else if let Ok(hex) = u32::from_str_radix(unicode_number, 16) {
|
||||
if let Some(character) = std::char::from_u32(hex) {
|
||||
// scalar
|
||||
return Some(Char::Scalar(character));
|
||||
return Ok(Char::Scalar(character));
|
||||
} else if hex <= 0x10FFFF {
|
||||
return Some(Char::NonScalar(hex));
|
||||
return Ok(Char::NonScalar(hex));
|
||||
} else {
|
||||
return Err(ParserError::lexer_invalid_character_exceeded_max_value(unicode_number).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if input_tendril.to_string().chars().count() != 1 {
|
||||
return None;
|
||||
// If char doesn't close.
|
||||
return Err(ParserError::lexer_char_not_closed(&input_tendril[0..]).into());
|
||||
} else if let Some(character) = input_tendril.to_string().chars().next() {
|
||||
return Some(Char::Scalar(character));
|
||||
// If its a simple char.
|
||||
return Ok(Char::Scalar(character));
|
||||
}
|
||||
|
||||
// 0rphon: should be impossible to hit if function is used correctly
|
||||
panic!();
|
||||
None
|
||||
Err(ParserError::lexer_invalid_char(input_tendril.to_string()).into())
|
||||
}
|
||||
|
||||
///
|
||||
@ -150,18 +156,12 @@ impl Token {
|
||||
return Err(ParserError::lexer_eat_integer_leading_zero(String::from_utf8_lossy(input)).into());
|
||||
}
|
||||
let mut i = 1;
|
||||
let mut is_hex = false;
|
||||
|
||||
while i < input.len() {
|
||||
if i == 1 && input[0] == b'0' && input[i] == b'x' {
|
||||
is_hex = true;
|
||||
i += 1;
|
||||
continue;
|
||||
return Err(ParserError::lexer_hex_number_provided(&input_tendril[0..3]).into());
|
||||
}
|
||||
if is_hex {
|
||||
if !input[i].is_ascii_hexdigit() {
|
||||
break;
|
||||
}
|
||||
} else if !input[i].is_ascii_digit() {
|
||||
if !input[i].is_ascii_digit() {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ impl Token {
|
||||
}
|
||||
|
||||
/// Returns the number of bytes in an emoji via a bit mask.
|
||||
fn utf8_byte_count(byte: u8) -> u8 {
|
||||
fn utf8_byte_count(byte: u8) -> usize {
|
||||
let mut mask = 0x80;
|
||||
let mut result = 0;
|
||||
while byte & mask > 0 {
|
||||
@ -204,7 +204,7 @@ impl Token {
|
||||
x if x.is_ascii_whitespace() => return Ok((1, Token::WhiteSpace)),
|
||||
b'"' => {
|
||||
let mut i = 1;
|
||||
let mut len: u8 = 1;
|
||||
let mut len = 1;
|
||||
let mut start = 1;
|
||||
let mut in_escape = false;
|
||||
let mut escaped = false;
|
||||
@ -217,7 +217,7 @@ impl Token {
|
||||
// If it's an emoji get the length.
|
||||
if input[i] & 0x80 > 0 {
|
||||
len = Self::utf8_byte_count(input[i]);
|
||||
i += (len as usize) - 1;
|
||||
i += len - 1;
|
||||
}
|
||||
|
||||
if !in_escape {
|
||||
@ -255,26 +255,17 @@ impl Token {
|
||||
}
|
||||
|
||||
if !in_escape {
|
||||
match Self::eat_char(
|
||||
let character = Self::eat_char(
|
||||
input_tendril.subtendril(start as u32, len as u32),
|
||||
escaped,
|
||||
hex,
|
||||
unicode,
|
||||
) {
|
||||
Some(character) => {
|
||||
len = 1;
|
||||
escaped = false;
|
||||
hex = false;
|
||||
unicode = false;
|
||||
string.push(character.into());
|
||||
}
|
||||
None => {
|
||||
return Err(ParserError::lexer_expected_valid_escaped_char(
|
||||
input_tendril.subtendril(start as u32, len as u32),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
)?;
|
||||
len = 1;
|
||||
escaped = false;
|
||||
hex = false;
|
||||
unicode = false;
|
||||
string.push(character.into());
|
||||
}
|
||||
|
||||
i += 1;
|
||||
@ -295,14 +286,27 @@ impl Token {
|
||||
let mut in_escape = false;
|
||||
let mut escaped = false;
|
||||
let mut hex = false;
|
||||
let mut unicode = false;
|
||||
let mut escaped_unicode = false;
|
||||
let mut unicode_char = false;
|
||||
let mut end = false;
|
||||
|
||||
while i < input.len() {
|
||||
if !in_escape {
|
||||
if input[i] & 0x80 > 0 && !unicode_char {
|
||||
i += Self::utf8_byte_count(input[i]);
|
||||
unicode_char = true;
|
||||
continue;
|
||||
} else if input[i] & 0x80 > 0 && unicode_char {
|
||||
i += Self::utf8_byte_count(input[i]);
|
||||
return Err(ParserError::lexer_invalid_char(&input_tendril[0..i]).into());
|
||||
} else if !in_escape || unicode_char {
|
||||
if input[i] == b'\'' {
|
||||
end = true;
|
||||
break;
|
||||
} else if unicode_char {
|
||||
return Err(ParserError::lexer_invalid_char(
|
||||
&input_tendril[0..input_tendril[1..].find('\'').unwrap_or(i + 1)],
|
||||
)
|
||||
.into());
|
||||
} else if input[i] == b'\\' {
|
||||
in_escape = true;
|
||||
}
|
||||
@ -311,7 +315,7 @@ impl Token {
|
||||
hex = true;
|
||||
} else if input[i] == b'u' {
|
||||
if input[i + 1] == b'{' {
|
||||
unicode = true;
|
||||
escaped_unicode = true;
|
||||
} else {
|
||||
return Err(ParserError::lexer_expected_valid_escaped_char(input[i]).into());
|
||||
}
|
||||
@ -329,10 +333,13 @@ impl Token {
|
||||
return Err(ParserError::lexer_char_not_closed(String::from_utf8_lossy(&input[0..i])).into());
|
||||
}
|
||||
|
||||
return match Self::eat_char(input_tendril.subtendril(1, (i - 1) as u32), escaped, hex, unicode) {
|
||||
Some(character) => Ok((i + 1, Token::CharLit(character))),
|
||||
None => Err(ParserError::lexer_invalid_char(String::from_utf8_lossy(&input[0..i - 1])).into()),
|
||||
};
|
||||
let character = Self::eat_char(
|
||||
input_tendril.subtendril(1, (i - 1) as u32),
|
||||
escaped,
|
||||
hex,
|
||||
escaped_unicode,
|
||||
)?;
|
||||
return Ok((i + 1, Token::CharLit(character)));
|
||||
}
|
||||
x if x.is_ascii_digit() => {
|
||||
return Self::eat_integer(&input_tendril);
|
||||
|
@ -58,7 +58,7 @@ pub(crate) fn tokenize(path: &str, input: StrTendril) -> Result<Vec<SpannedToken
|
||||
path,
|
||||
input.subtendril(
|
||||
line_start as u32,
|
||||
input[line_start..].find('\n').unwrap_or_else(|| input.len()) as u32,
|
||||
input[line_start..].find('\n').unwrap_or(input.len()) as u32,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -654,16 +654,6 @@ integer = [ "-" ] natural
|
||||
Go to: _[natural](#user-content-natural)_;
|
||||
|
||||
|
||||
An untyped literal is just an integer.
|
||||
|
||||
<a name="untyped-literal"></a>
|
||||
```abnf
|
||||
untyped-literal = integer
|
||||
```
|
||||
|
||||
Go to: _[integer](#user-content-integer)_;
|
||||
|
||||
|
||||
Unsigned literals are naturals followed by unsigned types.
|
||||
|
||||
<a name="unsigned-literal"></a>
|
||||
@ -849,8 +839,7 @@ as defined by the following rule.
|
||||
|
||||
<a name="atomic-literal"></a>
|
||||
```abnf
|
||||
atomic-literal = untyped-literal
|
||||
/ unsigned-literal
|
||||
atomic-literal = unsigned-literal
|
||||
/ signed-literal
|
||||
/ field-literal
|
||||
/ product-group-literal
|
||||
@ -860,7 +849,7 @@ atomic-literal = untyped-literal
|
||||
/ string-literal
|
||||
```
|
||||
|
||||
Go to: _[address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [character-literal](#user-content-character-literal), [field-literal](#user-content-field-literal), [product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal), [string-literal](#user-content-string-literal), [unsigned-literal](#user-content-unsigned-literal), [untyped-literal](#user-content-untyped-literal)_;
|
||||
Go to: _[address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [character-literal](#user-content-character-literal), [field-literal](#user-content-field-literal), [product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal), [string-literal](#user-content-string-literal), [unsigned-literal](#user-content-unsigned-literal)_;
|
||||
|
||||
|
||||
After defining the (mostly) alphanumeric tokens above,
|
||||
@ -1013,34 +1002,24 @@ An array type consists of an element type
|
||||
and an indication of dimensions.
|
||||
There is either a single dimension,
|
||||
or a tuple of one or more dimensions.
|
||||
Each dimension is either a natural or is unspecified.
|
||||
Each dimension is a natural.
|
||||
|
||||
<a name="array-type"></a>
|
||||
```abnf
|
||||
array-type = "[" type ";" array-type-dimensions "]"
|
||||
array-type = "[" type ";" array-dimensions "]"
|
||||
```
|
||||
|
||||
Go to: _[array-type-dimensions](#user-content-array-type-dimensions), [type](#user-content-type)_;
|
||||
Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_;
|
||||
|
||||
|
||||
<a name="array-type-dimension"></a>
|
||||
<a name="array-dimensions"></a>
|
||||
```abnf
|
||||
array-type-dimension = natural / "_"
|
||||
array-dimensions = natural / "(" natural *( "," natural ) ")"
|
||||
```
|
||||
|
||||
Go to: _[natural](#user-content-natural)_;
|
||||
|
||||
|
||||
<a name="array-type-dimensions"></a>
|
||||
```abnf
|
||||
array-type-dimensions = array-type-dimension
|
||||
/ "(" array-type-dimension
|
||||
*( "," array-type-dimension ) [","] ")"
|
||||
```
|
||||
|
||||
Go to: _[array-type-dimension](#user-content-array-type-dimension)_;
|
||||
|
||||
|
||||
The keyword `Self` denotes the enclosing circuit type.
|
||||
It is only allowed inside a circuit type declaration.
|
||||
|
||||
@ -1214,19 +1193,10 @@ Go to: _[expression](#user-content-expression)_;
|
||||
|
||||
<a name="array-repeat-construction"></a>
|
||||
```abnf
|
||||
array-repeat-construction = "[" expression ";" array-expression-dimensions "]"
|
||||
array-repeat-construction = "[" expression ";" array-dimensions "]"
|
||||
```
|
||||
|
||||
Go to: _[array-expression-dimensions](#user-content-array-expression-dimensions), [expression](#user-content-expression)_;
|
||||
|
||||
|
||||
<a name="array-expression-dimensions"></a>
|
||||
```abnf
|
||||
array-expression-dimensions = natural
|
||||
/ "(" natural *( "," natural ) ")"
|
||||
```
|
||||
|
||||
Go to: _[natural](#user-content-natural)_;
|
||||
Go to: _[array-dimensions](#user-content-array-dimensions), [expression](#user-content-expression)_;
|
||||
|
||||
|
||||
<a name="array-construction"></a>
|
||||
@ -1511,7 +1481,7 @@ and just one initializing expression.
|
||||
|
||||
<a name="variable-declaration"></a>
|
||||
```abnf
|
||||
variable-declaration = %s"let" identifier-or-identifiers [ ":" type ]
|
||||
variable-declaration = %s"let" identifier-or-identifiers ":" type
|
||||
"=" expression ";"
|
||||
```
|
||||
|
||||
@ -1520,7 +1490,7 @@ Go to: _[expression](#user-content-expression), [identifier-or-identifiers](#use
|
||||
|
||||
<a name="constant-declaration"></a>
|
||||
```abnf
|
||||
constant-declaration = %s"const" identifier-or-identifiers [ ":" type ]
|
||||
constant-declaration = %s"const" identifier-or-identifiers ":" type
|
||||
"=" expression ";"
|
||||
```
|
||||
|
||||
@ -1566,11 +1536,12 @@ The body is a block.
|
||||
|
||||
<a name="loop-statement"></a>
|
||||
```abnf
|
||||
loop-statement = %s"for" identifier %s"in" expression ".." [ "=" ] expression
|
||||
loop-statement = %s"for" identifier ":" type
|
||||
%s"in" expression ".." [ "=" ] expression
|
||||
block
|
||||
```
|
||||
|
||||
Go to: _[block](#user-content-block), [expression](#user-content-expression), [identifier](#user-content-identifier)_;
|
||||
Go to: _[block](#user-content-block), [expression](#user-content-expression), [identifier](#user-content-identifier), [type](#user-content-type)_;
|
||||
|
||||
|
||||
An assignment statement is straightforward.
|
||||
|
@ -461,10 +461,6 @@ natural = 1*decimal-digit
|
||||
|
||||
integer = [ "-" ] natural
|
||||
|
||||
; An untyped literal is just an integer.
|
||||
|
||||
untyped-literal = integer
|
||||
|
||||
; Unsigned literals are naturals followed by unsigned types.
|
||||
|
||||
unsigned-literal = natural ( %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" )
|
||||
@ -552,8 +548,7 @@ string-literal-element = not-double-quote-or-backslash
|
||||
; (in the sense that they are tokens, without whitespace allowed in them),
|
||||
; as defined by the following rule.
|
||||
|
||||
atomic-literal = untyped-literal
|
||||
/ unsigned-literal
|
||||
atomic-literal = unsigned-literal
|
||||
/ signed-literal
|
||||
/ field-literal
|
||||
/ product-group-literal
|
||||
@ -650,15 +645,11 @@ tuple-type = "(" [ type 1*( "," type ) ] ")"
|
||||
; and an indication of dimensions.
|
||||
; There is either a single dimension,
|
||||
; or a tuple of one or more dimensions.
|
||||
; Each dimension is either a natural or is unspecified.
|
||||
; Each dimension is a natural.
|
||||
|
||||
array-type = "[" type ";" array-type-dimensions "]"
|
||||
array-type = "[" type ";" array-dimensions "]"
|
||||
|
||||
array-type-dimension = natural / "_"
|
||||
|
||||
array-type-dimensions = array-type-dimension
|
||||
/ "(" array-type-dimension
|
||||
*( "," array-type-dimension ) [","] ")"
|
||||
array-dimensions = natural / "(" natural *( "," natural ) ")"
|
||||
|
||||
; The keyword `Self` denotes the enclosing circuit type.
|
||||
; It is only allowed inside a circuit type declaration.
|
||||
@ -756,10 +747,7 @@ array-inline-construction = "["
|
||||
|
||||
array-inline-element = expression / "..." expression
|
||||
|
||||
array-repeat-construction = "[" expression ";" array-expression-dimensions "]"
|
||||
|
||||
array-expression-dimensions = natural
|
||||
/ "(" natural *( "," natural ) ")"
|
||||
array-repeat-construction = "[" expression ";" array-dimensions "]"
|
||||
|
||||
array-construction = array-inline-construction / array-repeat-construction
|
||||
|
||||
@ -918,10 +906,10 @@ return-statement = %s"return" expression ";"
|
||||
; in all cases, there is just one optional type
|
||||
; and just one initializing expression.
|
||||
|
||||
variable-declaration = %s"let" identifier-or-identifiers [ ":" type ]
|
||||
variable-declaration = %s"let" identifier-or-identifiers ":" type
|
||||
"=" expression ";"
|
||||
|
||||
constant-declaration = %s"const" identifier-or-identifiers [ ":" type ]
|
||||
constant-declaration = %s"const" identifier-or-identifiers ":" type
|
||||
"=" expression ";"
|
||||
|
||||
identifier-or-identifiers = identifier
|
||||
@ -943,7 +931,8 @@ conditional-statement = branch
|
||||
; that goes from a starting value (inclusive) to an ending value (exclusive).
|
||||
; The body is a block.
|
||||
|
||||
loop-statement = %s"for" identifier %s"in" expression ".." [ "=" ] expression
|
||||
loop-statement = %s"for" identifier ":" type
|
||||
%s"in" expression ".." [ "=" ] expression
|
||||
block
|
||||
|
||||
; An assignment statement is straightforward.
|
||||
|
@ -1,6 +1,5 @@
|
||||
[main]
|
||||
a: u32 = 1;
|
||||
b: u32 = 2;
|
||||
y: bool = true;
|
||||
|
||||
[registers]
|
||||
r0: u32 = 0;
|
||||
r0: bool = false;
|
||||
|
@ -1,5 +1,11 @@
|
||||
// The 'hello-world' main function.
|
||||
function main(a: u32, b: u32) -> u32 {
|
||||
let c: u32 = a + b;
|
||||
return c;
|
||||
type str = [char; _];
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
let s = "abc";
|
||||
return (first_el(s) == 'a') == y;
|
||||
}
|
||||
|
||||
function first_el(s: str) -> char {
|
||||
return s[0];
|
||||
}
|
||||
|
@ -312,12 +312,4 @@ create_errors!(
|
||||
msg: format!("Tried to assign to static member `{}`", member),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when arrays with unspecified size are used in main.
|
||||
@formatted
|
||||
input_array_size_must_be_specified {
|
||||
args: (),
|
||||
msg: "arrays in main function input must have known size",
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -46,14 +46,6 @@ create_errors!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when [`ArrayDimensions`] are not specified.
|
||||
@formatted
|
||||
array_dimensions_must_be_specified {
|
||||
args: (),
|
||||
msg: "array dimensions must be specified",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when array init is using spread.
|
||||
@formatted
|
||||
array_spread_is_not_allowed {
|
||||
|
@ -236,23 +236,23 @@ create_errors!(
|
||||
@backtraced
|
||||
lexer_eat_integer_leading_zero {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Tried to eat integer but found a leading zero on {}.", input),
|
||||
msg: format!("Tried to eat integer but found a leading zero on `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When an integer is started with a leading zero.
|
||||
@backtraced
|
||||
lexer_expected_valid_escaped_char {
|
||||
lexer_expected_valid_escaped_char {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Expected a valid escape character but found {}.", input),
|
||||
msg: format!("Expected a valid escape character but found `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// When a string is not properly closed.
|
||||
@backtraced
|
||||
lexer_string_not_closed {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Expected a closed string but found {}.", input),
|
||||
msg: format!("Expected a closed string but found `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -260,7 +260,7 @@ create_errors!(
|
||||
@backtraced
|
||||
lexer_char_not_closed {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Expected a closed char but found {}.", input),
|
||||
msg: format!("Expected a closed char but found `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ create_errors!(
|
||||
@backtraced
|
||||
lexer_invalid_char {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Expected valid character but found {}.", input),
|
||||
msg: format!("Expected valid character but found `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -284,7 +284,7 @@ create_errors!(
|
||||
@backtraced
|
||||
lexer_block_comment_does_not_close_before_eof {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Block comment does not close with content: {}.", input),
|
||||
msg: format!("Block comment does not close with content: `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -292,7 +292,78 @@ create_errors!(
|
||||
@backtraced
|
||||
could_not_lex {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Could not lex the following content: {}.", input),
|
||||
msg: format!("Could not lex the following content: `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escaped character was given more than one char to escape.
|
||||
@backtraced
|
||||
lexer_escaped_char_incorrect_length {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Could not lex the following escaped char due to being given more than one char: `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escape was given but no following character
|
||||
@backtraced
|
||||
lexer_unclosed_escaped_char {
|
||||
args: (),
|
||||
msg: "There was no escaped character following the escape char symbol `\\`.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escaped hex was given more than two chars to escape.
|
||||
@backtraced
|
||||
lexer_escaped_hex_incorrect_length {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Could not lex the following escaped hex due to being given more than two chars: `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a valid hex character was expected.
|
||||
@backtraced
|
||||
lexer_expected_valid_hex_char {
|
||||
args: (input: impl Display),
|
||||
msg: format!("Expected a valid hex character but found `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escaped unicode char was given but no following closing symbol.
|
||||
@backtraced
|
||||
lexer_unclosed_escaped_unicode_char {
|
||||
args: (input: impl Display),
|
||||
msg: format!("There was no closing `}}` after a escaped unicode `{}`.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escaped unicode char was given but it had an incorrect length.
|
||||
@backtraced
|
||||
lexer_invalid_escaped_unicode_length {
|
||||
args: (input: impl Display),
|
||||
msg: format!("The escaped unicode char `{}` is not within valid length of [1, 6].", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a escaped unicode char was given but exceeded maximum value.
|
||||
@backtraced
|
||||
lexer_invalid_character_exceeded_max_value {
|
||||
args: (input: impl Display),
|
||||
msg: format!("The escaped unicode char `{}` is greater than 0x10FFFF.", input),
|
||||
help: None,
|
||||
}
|
||||
/// When a hex number is provided.
|
||||
@backtraced
|
||||
lexer_hex_number_provided {
|
||||
args: (input: impl Display),
|
||||
msg: format!("A hex number `{}..` was provided but hex is not allowed.", input),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// When a function recieved a self argument outside the first argument.
|
||||
@backtraced
|
||||
parser_self_outside_first_argument {
|
||||
args: (),
|
||||
msg: "A function received a self argument as not the first argument.",
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
function main() {
|
||||
let x: [u8; _] = [1u8,2];
|
||||
let z: bool = x == [1u8,2,3]; // array size mismatch
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
let d: [u8; _] = [1,2,3,4];
|
||||
return d == [1,2,3,4];
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
return (first_el([1,2,3,4]) == 1) == y;
|
||||
}
|
||||
|
||||
function first_el(arr: [u8; _]) -> u8 {
|
||||
return arr[0];
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
[main]
|
||||
y: bool = true;
|
||||
n: bool = false;
|
||||
a: [char; 11] = "hello world";
|
||||
|
||||
[registers]
|
||||
r0: bool = false;
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(a: [char; 11], y: bool) -> bool {
|
||||
return y == (a.len() == 11);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
let x = 0u8;
|
||||
for i in 0..strlen("I swear to god I had something for this") {
|
||||
x += 1;
|
||||
}
|
||||
return (x == 39) == y;
|
||||
}
|
||||
|
||||
function strlen(str: [char; _]) -> u32 {
|
||||
return str.len();
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
type str = [char; _];
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
let s = "abc";
|
||||
return (first_el(s) == 'a') == y;
|
||||
}
|
||||
|
||||
function first_el(s: str) -> char {
|
||||
return s[0];
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ECMP0376093]: array sizes must match for comparison; left: 2, right: 3\n --> compiler-test:5:19\n |\n 5 | let z: bool = x == [1u8,2,3]; // array size mismatch\n | ^^^^^^^^^^^^^^"
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 1
|
||||
num_constraints: 1
|
||||
at: 042610d0fd1fe6d6ac112138f8755752f44c7d2a00f1b5960574d6da5cda393f
|
||||
bt: e97756698880ab7555a959a5fb5c6b4e15bd64612aa677adbfe2d0bd91f0a83c
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: 71e25416f4a31045a847f29df48d5e9cce19d0df31c479761f2387eca4bb759f
|
||||
imports_resolved_ast: a408ca2965d8d63856b1f95385746d5be9825b646e7f97a5fd3203638681292c
|
||||
canonicalized_ast: a408ca2965d8d63856b1f95385746d5be9825b646e7f97a5fd3203638681292c
|
||||
type_inferenced_ast: 88e5b982b094f07cc0337812b4965b655c020bdebfa1ad7ac8fd2ddd3c730b8b
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 1
|
||||
num_constraints: 1
|
||||
at: 042610d0fd1fe6d6ac112138f8755752f44c7d2a00f1b5960574d6da5cda393f
|
||||
bt: e97756698880ab7555a959a5fb5c6b4e15bd64612aa677adbfe2d0bd91f0a83c
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: d6d3ebe6a0b7f19e51d245d715706122577777a8325459df7db2c08ee5f841bd
|
||||
imports_resolved_ast: 675c0542777db276ce7a39decb9dc5aacfde6b00ebfeb3982c480ed531a79be5
|
||||
canonicalized_ast: 675c0542777db276ce7a39decb9dc5aacfde6b00ebfeb3982c480ed531a79be5
|
||||
type_inferenced_ast: ae8cbfc3938971fc0e42fa400b1277d288ea4b7d4d8149b452fce81ae4813315
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 12
|
||||
num_constraints: 1
|
||||
at: 336f487fe39f24aef980deaaf7d6dddcc0dbfa8f121c3470b05546c1ac13f87e
|
||||
bt: ae35381db5558456a49acb22132b4930efd53b90eb2668df06c5d9c1a6b0ab9f
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: be4b4279f79a35306e1edf5086275a2b216e9d46d66b9bb5fbf650062b7cd263
|
||||
imports_resolved_ast: c4aae9410df8034a7744ec5f1998454bacde915ddaadfab42181528f1923f742
|
||||
canonicalized_ast: c4aae9410df8034a7744ec5f1998454bacde915ddaadfab42181528f1923f742
|
||||
type_inferenced_ast: 0f8434f9e0430dc238602c0479a928be87101566dc0e9ae60ab9f4f1339ef313
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 1
|
||||
num_constraints: 1
|
||||
at: 042610d0fd1fe6d6ac112138f8755752f44c7d2a00f1b5960574d6da5cda393f
|
||||
bt: e97756698880ab7555a959a5fb5c6b4e15bd64612aa677adbfe2d0bd91f0a83c
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: cb9419739db39f806ff96983f53aa085a96238833ed754293042724dd3b29704
|
||||
imports_resolved_ast: 675a67a8dae0a33a273d74ec021df0e23c5ed7cb32faf8efd2d2f087979de039
|
||||
canonicalized_ast: b75d02c7cadbcd2906ad0d7b6376bbdc32ff1f26348913e2b0a84ced7496a2f6
|
||||
type_inferenced_ast: 87ee95068efb0a58e18f2e3b8668db8d2ad9826b21e8b8ce6bc26f60c9fe88ca
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 4
|
||||
num_constraints: 5
|
||||
at: e2c343f33b3c986318d821645015951a2f3fb198915bbf602e2c3e58ebfb9c73
|
||||
bt: 71744948a918814d3008831b4b73101a5cf7346e6ff62d98968eb8b3b91aa343
|
||||
ct: 94757fb2316d68d18fd26e96a2992b03a8db8d49d802b34201dce6f12518676b
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: 712ed2b7c1ddf180a39cd1bf83c7a4ca3de909a14f87250ec445ba6ae6aa6597
|
||||
imports_resolved_ast: 36d9e14cf42065047dc21a5c68f45d3264dc0d38eb53355d3f9fef7bd7d512b1
|
||||
canonicalized_ast: f1edababa6847e2ca24a0786bc1a0b2e66f0d60f5b11c59a24c8b1503f893092
|
||||
type_inferenced_ast: c979556f787eb3190b0c4cec3d5a6baabbf64d32f7e3281c784f83262da33205
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Parse
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370041]: A function received a self argument as not the first argument."
|
@ -2,43 +2,41 @@
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370028]: Expected a closed char but found '\\'."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found 'a."
|
||||
- "Error [EPAR0370029]: Expected valid character but found ."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x9."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x7."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x8."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\xc."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\xc."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\xD."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\xC."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\xe."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\x9."
|
||||
- "Error [EPAR0370029]: Expected valid character but found 'abcdef."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\t\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\u{bbbbb}\\u{aaaa."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\u{2764."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\u{276g."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found 117."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '\\u{110000."
|
||||
- "Error [EPAR0370029]: Expected valid character but found '😭😂<F09F98AD>."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found '\u001d<31>x 9 i32."
|
||||
- "Error [EPAR0370029]: Expected valid character but found ' //#1647."
|
||||
- "Error [EPAR0370029]: Expected valid character but found ' //#1651."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found `'\\'`."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found `'a`."
|
||||
- "Error [EPAR0370024]: Expected more characters to lex but found none."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `154`."
|
||||
- "Error [EPAR0370035]: Could not lex the following escaped hex due to being given more than two chars: `7`."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found `\\x7g`."
|
||||
- "Error [EPAR0370035]: Could not lex the following escaped hex due to being given more than two chars: `z`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `128`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `193`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `194`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `223`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `192`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `224`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `159`."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found `abcdefg`."
|
||||
- "Error [EPAR0370033]: Could not lex the following escaped char due to being given more than one char: `t\\t`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `a`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `z`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `A`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `Z`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `1`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `9`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `*`."
|
||||
- "Error [EPAR0370035]: Could not lex the following escaped hex due to being given more than two chars: ``."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370038]: The escaped unicode char `bbbbb}\\u{aaaa` is not within valid length of [1, 6]."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370037]: There was no closing `}` after a escaped unicode `\\u{2764z`."
|
||||
- "Error [EPAR0370028]: Expected a closed char but found `\\u{276g}`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `117`."
|
||||
- "Error [EPAR0370039]: The escaped unicode char `110000` is greater than 0x10FFFF."
|
||||
- "Error [EPAR0370037]: There was no closing `}` after a escaped unicode `\\u{af🦀`."
|
||||
- "Error [EPAR0370029]: Expected valid character but found `'🦀\\`."
|
||||
- "Error [EPAR0370029]: Expected valid character but found `'😭😂`."
|
||||
|
@ -2,11 +2,10 @@
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"Hello world!."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"\\\"."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"\\."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found \\l."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"\\uaaa\"."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"\\u\"."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found \\xFF."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found \"\\x\"."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found `\"Hello world!`."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found `\"\\\"`."
|
||||
- "Error [EPAR0370026]: Expected a valid escape character but found `l`."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found `\"\\uaaa\"`."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found `\"\\u\"`."
|
||||
- "Error [EPAR0370036]: Expected a valid hex character but found `255`."
|
||||
- "Error [EPAR0370027]: Expected a closed string but found `\"\\x\"`."
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Parse
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'ident', got '?'\n --> test:3:6\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370009]: unexpected string: expected 'ident', got '?'\n --> test:3:14\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370009]: unexpected string: expected 'ident', got '123'\n --> test:8:6\n |\n 8 | @bar(123) // ints not vali\n | ^^^\nError [EPAR0370017]: \"@context(...)\" is deprecated. Did you mean @test annotation?\n --> test:14:2\n |\n 14 | @context // recovery witness\n | ^^^^^^^"
|
@ -2,4 +2,4 @@
|
||||
namespace: Parse
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'ident or int', got '?'\n --> test:3:6\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370009]: unexpected string: expected 'ident or int', got '?'\n --> test:3:14\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370017]: \"@context(...)\" is deprecated. Did you mean @test annotation?\n --> test:8:2\n |\n 8 | @context // recovery witness\n | ^^^^^^^"
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'ident', got '?'\n --> test:3:6\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370009]: unexpected string: expected 'ident', got '?'\n --> test:3:14\n |\n 3 | @foo(?, bar, ?)\n | ^\nError [EPAR0370017]: \"@context(...)\" is deprecated. Did you mean @test annotation?\n --> test:8:2\n |\n 8 | @context // recovery witness\n | ^^^^^^^"
|
||||
|
@ -1,68 +0,0 @@
|
||||
---
|
||||
namespace: Parse
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- name: ""
|
||||
expected_input: []
|
||||
import_statements: []
|
||||
imports: {}
|
||||
aliases: {}
|
||||
circuits: {}
|
||||
global_consts: {}
|
||||
functions:
|
||||
"{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":10,\\\"col_stop\\\":11,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function x(x: [u8; _]) {\\\"}\"}":
|
||||
annotations: {}
|
||||
identifier: "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":10,\\\"col_stop\\\":11,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function x(x: [u8; _]) {\\\"}\"}"
|
||||
input:
|
||||
- Variable:
|
||||
identifier: "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":12,\\\"col_stop\\\":13,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function x(x: [u8; _]) {\\\"}\"}"
|
||||
const_: false
|
||||
mutable: true
|
||||
type_:
|
||||
Array:
|
||||
- IntegerType: U8
|
||||
- - value: "0"
|
||||
span:
|
||||
line_start: 3
|
||||
line_stop: 3
|
||||
col_start: 12
|
||||
col_stop: 13
|
||||
path: ""
|
||||
content: "function x(x: [u8; _]) {"
|
||||
const_: false
|
||||
output: ~
|
||||
core_mapping: ~
|
||||
block:
|
||||
statements:
|
||||
- Return:
|
||||
expression:
|
||||
TupleInit:
|
||||
elements: []
|
||||
span:
|
||||
line_start: 4
|
||||
line_stop: 4
|
||||
col_start: 12
|
||||
col_stop: 14
|
||||
path: ""
|
||||
content: " return ();"
|
||||
span:
|
||||
line_start: 4
|
||||
line_stop: 4
|
||||
col_start: 5
|
||||
col_stop: 14
|
||||
path: ""
|
||||
content: " return ();"
|
||||
span:
|
||||
line_start: 3
|
||||
line_stop: 5
|
||||
col_start: 24
|
||||
col_stop: 2
|
||||
path: ""
|
||||
content: "function x(x: [u8; _]) {\n ...\n}"
|
||||
span:
|
||||
line_start: 3
|
||||
line_stop: 5
|
||||
col_start: 1
|
||||
col_stop: 2
|
||||
path: ""
|
||||
content: "function x(x: [u8; _]) {\n ...\n}"
|
@ -1513,53 +1513,6 @@ outputs:
|
||||
col_stop: 14
|
||||
path: ""
|
||||
content: "let (x,) = ();"
|
||||
- Definition:
|
||||
declaration_type: Let
|
||||
variable_names:
|
||||
- mutable: true
|
||||
identifier: "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"let x: [char; _] = \\\\\\\"Hello, World!\\\\\\\";\\\"}\"}"
|
||||
span:
|
||||
line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 5
|
||||
col_stop: 6
|
||||
path: ""
|
||||
content: "let x: [char; _] = \"Hello, World!\";"
|
||||
parened: false
|
||||
type_:
|
||||
Array:
|
||||
- Char
|
||||
- - value: "0"
|
||||
value:
|
||||
Value:
|
||||
String:
|
||||
- - Scalar: 72
|
||||
- Scalar: 101
|
||||
- Scalar: 108
|
||||
- Scalar: 108
|
||||
- Scalar: 111
|
||||
- Scalar: 44
|
||||
- Scalar: 32
|
||||
- Scalar: 87
|
||||
- Scalar: 111
|
||||
- Scalar: 114
|
||||
- Scalar: 108
|
||||
- Scalar: 100
|
||||
- Scalar: 33
|
||||
- span:
|
||||
line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 20
|
||||
col_stop: 35
|
||||
path: ""
|
||||
content: "let x: [char; _] = \"Hello, World!\";"
|
||||
span:
|
||||
line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 35
|
||||
path: ""
|
||||
content: "let x: [char; _] = \"Hello, World!\";"
|
||||
- Definition:
|
||||
declaration_type: Let
|
||||
variable_names:
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
namespace: ParseStatement
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370040]: A hex number `0x4..` was provided but hex is not allowed."
|
||||
- "Error [EPAR0370040]: A hex number `0xA..` was provided but hex is not allowed."
|
||||
- "Error [EPAR0370040]: A hex number `0xF..` was provided but hex is not allowed."
|
10
tests/parser/circuits/self_not_first_fail.leo
Normal file
10
tests/parser/circuits/self_not_first_fail.leo
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
namespace: Parse
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
circuit X {
|
||||
function x(foo: u32, &self) {
|
||||
return ();
|
||||
}
|
||||
}
|
@ -9,8 +9,6 @@ expectation: Fail
|
||||
|
||||
''
|
||||
|
||||
'\
|
||||
|
||||
'\x9A'
|
||||
'\x7'
|
||||
'\x7g'
|
||||
@ -46,8 +44,7 @@ expectation: Fail
|
||||
'\u01000000'
|
||||
'\u9999999'
|
||||
'\u{110000}'
|
||||
'\u{af🦀'
|
||||
'🦀\n'
|
||||
|
||||
'😭😂😘'
|
||||
'<1D>x 9 i32
|
||||
' //#1647 '\u{af🦀'
|
||||
' //#1651 '🦀\n'
|
@ -8,6 +8,12 @@ function x() {
|
||||
return ();
|
||||
}
|
||||
|
||||
@bar(123) // ints not vali
|
||||
function x() {
|
||||
return ();
|
||||
}
|
||||
|
||||
|
||||
@context // recovery witness
|
||||
function x() {
|
||||
return ();
|
@ -1,8 +0,0 @@
|
||||
/*
|
||||
namespace: Parse
|
||||
expectation: Pass
|
||||
*/
|
||||
|
||||
function x(x: [u8; _]) {
|
||||
return ();
|
||||
}
|
@ -99,9 +99,6 @@ let (x,y,) = ();
|
||||
|
||||
let (x,) = ();
|
||||
|
||||
|
||||
let x: [char; _] = "Hello, World!";
|
||||
|
||||
let x: [[u8; 2]; 2] = [[0,0], [0,0]];
|
||||
|
||||
let x: [u8; (2, 2)] = [[0,0], [0,0]];
|
||||
|
10
tests/parser/statement/hex_int_fail.leo
Normal file
10
tests/parser/statement/hex_int_fail.leo
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
namespace: ParseStatement
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
let x = 0x40u32;
|
||||
|
||||
let y: u32 = 0xAAu32;
|
||||
|
||||
let z = 0xFFu8;
|
@ -22,7 +22,7 @@ pub fn find_tests<T: AsRef<Path>>(path: T, out: &mut Vec<(String, String)>) {
|
||||
if entry.is_dir() {
|
||||
find_tests(entry.as_path(), out);
|
||||
continue;
|
||||
} else if entry.extension().map(|x| x.to_str()).flatten().unwrap_or_default() != "leo" {
|
||||
} else if entry.extension().and_then(|x| x.to_str()).unwrap_or_default() != "leo" {
|
||||
continue;
|
||||
}
|
||||
let content = fs::read_to_string(entry.as_path()).expect("failed to read test");
|
||||
|
@ -147,7 +147,7 @@ pub fn run_tests<T: Runner>(runner: &T, expectation_category: &str) {
|
||||
|
||||
let mut expected_output = expectations.as_ref().map(|x| x.outputs.iter());
|
||||
for (i, test) in tests.into_iter().enumerate() {
|
||||
let expected_output = expected_output.as_mut().map(|x| x.next()).flatten().cloned();
|
||||
let expected_output = expected_output.as_mut().and_then(|x| x.next()).cloned();
|
||||
println!("running test {} @ '{}'", test_name, path.to_str().unwrap());
|
||||
let output = namespace.run_test(Test {
|
||||
name: test_name.clone(),
|
||||
|
Loading…
Reference in New Issue
Block a user