mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 10:12:21 +03:00
input string syntax
This commit is contained in:
parent
8cb1dc6e30
commit
1c57eb4196
@ -17,7 +17,7 @@
|
||||
use crate::{ArrayDimensions, GroupValue};
|
||||
use leo_input::{
|
||||
errors::InputParserError,
|
||||
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression, TupleExpression},
|
||||
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression, StringExpression, TupleExpression},
|
||||
types::{ArrayType, DataType, IntegerType, TupleType, Type},
|
||||
values::{
|
||||
Address,
|
||||
@ -115,11 +115,59 @@ impl InputValue {
|
||||
(Type::Array(array_type), Expression::ArrayInitializer(initializer)) => {
|
||||
InputValue::from_array_initializer(array_type, initializer)
|
||||
}
|
||||
(Type::Array(array_type), Expression::StringExpression(string)) => {
|
||||
InputValue::from_string(array_type, string)
|
||||
}
|
||||
(Type::Tuple(tuple_type), Expression::Tuple(tuple)) => InputValue::from_tuple(tuple_type, tuple),
|
||||
(type_, expression) => Err(InputParserError::expression_type_mismatch(type_, expression)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new `InputValue` from the given `ArrayType` and `StringExpression`.
|
||||
///
|
||||
pub(crate) fn from_string(mut array_type: ArrayType, string: StringExpression) -> Result<Self, InputParserError> {
|
||||
// Create a new `ArrayDimensions` type from the input array_type dimensions.
|
||||
let array_dimensions_type = ArrayDimensions::from(array_type.dimensions.clone());
|
||||
|
||||
// Convert the array dimensions to usize.
|
||||
let array_dimensions = parse_array_dimensions(array_dimensions_type, &array_type.span)?;
|
||||
|
||||
// Return an error if the outer array dimension does not equal the number of array elements.
|
||||
if array_dimensions[0] != string.chars.len() {
|
||||
return Err(InputParserError::invalid_string_length(
|
||||
array_dimensions[0],
|
||||
string.chars.len(),
|
||||
&string.span,
|
||||
));
|
||||
}
|
||||
|
||||
array_type.dimensions = array_type.dimensions.next_dimension();
|
||||
|
||||
let inner_array_type = if array_dimensions.len() == 1 {
|
||||
// This is a single array
|
||||
*array_type.type_
|
||||
} else {
|
||||
// This is a multi-dimensional array
|
||||
return Err(InputParserError::invalid_string_dimensions(&array_type.span));
|
||||
};
|
||||
|
||||
let mut elements = Vec::with_capacity(string.chars.len());
|
||||
for character in string.chars.into_iter() {
|
||||
let element = InputValue::from_expression(
|
||||
inner_array_type.clone(),
|
||||
Expression::Value(Value::Char(CharValue {
|
||||
value: character.clone(),
|
||||
span: character.span().clone(),
|
||||
})),
|
||||
)?;
|
||||
|
||||
elements.push(element)
|
||||
}
|
||||
|
||||
Ok(InputValue::Array(elements))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new `InputValue` from the given `ArrayType` and `ArrayInlineExpression`.
|
||||
///
|
||||
|
@ -89,6 +89,21 @@ impl InputParserError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_string_dimensions(span: &Span) -> Self {
|
||||
let message = "String type defintion of a char array should not be multi-dimensional".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_string_length(expected: usize, received: usize, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Expected size of char array `{}` to match string size instead received `{}`",
|
||||
expected, received
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn implicit_type(data_type: DataType, implicit: NumberValue) -> Self {
|
||||
let message = format!("expected `{}`, found `{}`", data_type, implicit);
|
||||
|
||||
|
@ -25,6 +25,7 @@ use std::fmt;
|
||||
pub enum Expression<'ast> {
|
||||
ArrayInitializer(ArrayInitializerExpression<'ast>),
|
||||
ArrayInline(ArrayInlineExpression<'ast>),
|
||||
StringExpression(StringExpression<'ast>),
|
||||
Tuple(TupleExpression<'ast>),
|
||||
Value(Value<'ast>),
|
||||
}
|
||||
@ -34,6 +35,7 @@ impl<'ast> Expression<'ast> {
|
||||
match self {
|
||||
Expression::ArrayInitializer(expression) => &expression.span,
|
||||
Expression::ArrayInline(expression) => &expression.span,
|
||||
Expression::StringExpression(string) => &string.span,
|
||||
Expression::Tuple(tuple) => &tuple.span,
|
||||
Expression::Value(value) => value.span(),
|
||||
}
|
||||
@ -56,6 +58,7 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
||||
|
||||
write!(f, "array [{}]", values)
|
||||
}
|
||||
Expression::StringExpression(ref string) => write!(f, "{}", string),
|
||||
Expression::Tuple(ref tuple) => {
|
||||
let values = tuple
|
||||
.expressions
|
||||
|
@ -25,3 +25,6 @@ pub use expression::*;
|
||||
|
||||
pub mod tuple_expression;
|
||||
pub use tuple_expression::*;
|
||||
|
||||
pub mod string_expression;
|
||||
pub use string_expression::*;
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ast::Rule, values::CharValue};
|
||||
use crate::{ast::Rule, values::CharTypes};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
@ -23,17 +23,19 @@ use std::fmt;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
|
||||
#[pest_ast(rule(Rule::expression_string))]
|
||||
pub struct StringExpression<'ast> {
|
||||
pub chars: Vec<CharValue<'ast>>,
|
||||
pub chars: Vec<CharTypes<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for StringExpression<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\"")?;
|
||||
|
||||
for character in self.chars.iter() {
|
||||
write!(f, "{:?}", character)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
write!(f, "\"")
|
||||
}
|
||||
}
|
||||
|
@ -200,12 +200,16 @@ expression_array_initializer = { "[" ~ expression ~ ";" ~ array_dimensions ~ "]"
|
||||
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
|
||||
inline_array_inner = _{ (expression ~ ("," ~ NEWLINE* ~ expression)*)? }
|
||||
|
||||
// Declared in expressions/string_expression.rs
|
||||
expression_string = ${ "\"" ~ (!"\"" ~ char_types)+ ~ "\"" }
|
||||
|
||||
// Declared in expressions/expression.rs
|
||||
expression = {
|
||||
value
|
||||
| expression_tuple
|
||||
| expression_array_inline
|
||||
| expression_array_initializer
|
||||
| expression_string
|
||||
}
|
||||
expression_tuple = { "(" ~ expression ~ ("," ~ expression)+ ~")" }
|
||||
|
||||
|
@ -67,6 +67,17 @@ pub enum CharTypes<'ast> {
|
||||
Unicode(UnicodeChar<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> CharTypes<'ast> {
|
||||
pub fn span(&self) -> &Span<'ast> {
|
||||
match self {
|
||||
CharTypes::Basic(value) => &value.span,
|
||||
CharTypes::Escaped(value) => &value.span,
|
||||
CharTypes::Hex(value) => &value.span,
|
||||
CharTypes::Unicode(value) => &value.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> CharTypes<'ast> {
|
||||
pub fn inner(self) -> Result<char, InputParserError> {
|
||||
match self {
|
||||
@ -78,14 +89,23 @@ impl<'ast> CharTypes<'ast> {
|
||||
Err(InputParserError::invalid_char(character.value, &character.span))
|
||||
}
|
||||
Self::Escaped(character) => {
|
||||
if let Some(character) = character.value.chars().nth(1) {
|
||||
return Ok(character);
|
||||
if let Some(inner) = character.value.chars().nth(1) {
|
||||
return match inner {
|
||||
'0' => Ok(0 as char),
|
||||
't' => Ok(9 as char),
|
||||
'n' => Ok(10 as char),
|
||||
'r' => Ok(13 as char),
|
||||
'\"' => Ok(34 as char),
|
||||
'\'' => Ok(39 as char),
|
||||
'\\' => Ok(92 as char),
|
||||
_ => Err(InputParserError::invalid_char(character.value, &character.span)),
|
||||
};
|
||||
}
|
||||
|
||||
Err(InputParserError::invalid_char(character.value, &character.span))
|
||||
}
|
||||
Self::Hex(character) => {
|
||||
let hex_string_number = character.value[3..character.value.len()].to_string();
|
||||
let hex_string_number = character.value[2..character.value.len()].to_string();
|
||||
if let Ok(number) = u8::from_str_radix(&hex_string_number, 16) {
|
||||
if number < 127 {
|
||||
return Ok(number as char);
|
||||
|
@ -239,7 +239,7 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
if !end {
|
||||
if i == input.len() || i == 1 || !end {
|
||||
return (0, None);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ circuit Foo {
|
||||
s1: [char; 13];
|
||||
}
|
||||
|
||||
function takes_string(s: [char; 13]) -> bool {
|
||||
function takes_string(s: [char; 13]) -> [char; 13] {
|
||||
return s == `Hello, World!`;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ namespace: Compile
|
||||
expectation: Pass
|
||||
input_file:
|
||||
- inputs/string.in
|
||||
- inputs/weird.in
|
||||
*/
|
||||
|
||||
function main(s1: [char; 13], s2: [char; 4]) -> bool {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[main]
|
||||
s1: [char; 13] = ['H', 'e', 'l', 'l', 'o', ',', '\u{20}', 'W', 'o', 'r', 'l', 'd', '!'];
|
||||
s2: [char; 4] = ['t', 'e', 's', 't'];
|
||||
s1: [char; 13] = "Hello, World!";
|
||||
s2: [char; 4] = "test";
|
||||
|
||||
[registers]
|
||||
out: bool = true;
|
@ -1,6 +1,6 @@
|
||||
[main]
|
||||
s1: [char; 13] = ['H', 'e', 'l', 'l', 'o', ',', '\u{20}', 'W', 'o', 'r', 'l', 'd', '!'];
|
||||
s2: [char; 4] = ['t', 'e', 's', 't'];
|
||||
s1: [char; 13] = "Hello, World!";
|
||||
s2: [char; 4] = "test":
|
||||
|
||||
[registers]
|
||||
out: [char; 13] = ['H', 'e', 'l', 'l', 'o', ',', '\u{20}', 'W', 'o', 'r', 'l', 'd', '!'];
|
||||
out: [char; 13] = "Hello, World!";
|
6
tests/compiler/string/inputs/weird.in
Normal file
6
tests/compiler/string/inputs/weird.in
Normal file
@ -0,0 +1,6 @@
|
||||
[main]
|
||||
s1: [char; 13] = "\"ello, World\"";
|
||||
s2: [char; 4] = "\u{2764}\x2A\x09\u{2764}";
|
||||
|
||||
[registers]
|
||||
out: bool = true;
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
namespace: ParseExpression
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- " --> test:1:1\n |\n 1 | '\\'\n | ^\n |\n = unexpected token: '''"
|
||||
|
@ -0,0 +1,151 @@
|
||||
---
|
||||
namespace: ParseExpression
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- Value:
|
||||
String:
|
||||
- - s
|
||||
- t
|
||||
- r
|
||||
- i
|
||||
- n
|
||||
- g
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 9
|
||||
path: test
|
||||
content: "`string`"
|
||||
- Value:
|
||||
String:
|
||||
- - a
|
||||
- n
|
||||
- o
|
||||
- t
|
||||
- h
|
||||
- e
|
||||
- r
|
||||
- " "
|
||||
- "{"
|
||||
- " "
|
||||
- "}"
|
||||
- " "
|
||||
- s
|
||||
- t
|
||||
- r
|
||||
- i
|
||||
- n
|
||||
- g
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 21
|
||||
path: test
|
||||
content: "`another { } string`"
|
||||
- Value:
|
||||
String:
|
||||
- - "{"
|
||||
- " "
|
||||
- "]"
|
||||
- " "
|
||||
- "["
|
||||
- " "
|
||||
- ;
|
||||
- " "
|
||||
- a
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 12
|
||||
path: test
|
||||
content: "`{ ] [ ; a`"
|
||||
- Value:
|
||||
String:
|
||||
- -
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 10
|
||||
path: test
|
||||
content: "`\\u{FFA}`"
|
||||
- Value:
|
||||
String:
|
||||
- -
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 12
|
||||
path: test
|
||||
content: "`\\u{afafa}`"
|
||||
- Value:
|
||||
String:
|
||||
- - 꾯
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 11
|
||||
path: test
|
||||
content: "`\\u{afaf}`"
|
||||
- Value:
|
||||
String:
|
||||
- - ૺ
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 10
|
||||
path: test
|
||||
content: "`\\u{afa}`"
|
||||
- Value:
|
||||
String:
|
||||
- - ¯
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 9
|
||||
path: test
|
||||
content: "`\\u{af}`"
|
||||
- Value:
|
||||
String:
|
||||
- - "\n"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 8
|
||||
path: test
|
||||
content: "`\\u{a}`"
|
||||
- Value:
|
||||
String:
|
||||
- - "\n"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 7
|
||||
path: test
|
||||
content: "`\\x0A`"
|
||||
- Value:
|
||||
String:
|
||||
- - a
|
||||
- a
|
||||
- " "
|
||||
- "\\"
|
||||
- " "
|
||||
- "\""
|
||||
- " "
|
||||
- " "
|
||||
- "\n"
|
||||
- " "
|
||||
- a
|
||||
- a
|
||||
- " "
|
||||
- "\t"
|
||||
- " "
|
||||
- "\r"
|
||||
- " "
|
||||
- " "
|
||||
- "\u0000"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 28
|
||||
path: test
|
||||
content: "`aa \\\\ \\\" \\n aa \\t \\r \\0`"
|
@ -0,0 +1,15 @@
|
||||
---
|
||||
namespace: Token
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- "'\"string\"' @ 1:1-9"
|
||||
- "'\"another { } string\"' @ 1:1-21"
|
||||
- "'\"{ ] [ ; a\"' @ 1:1-12"
|
||||
- "'\"\"' @ 1:1-10"
|
||||
- "'\"\"' @ 1:1-12"
|
||||
- "'\"꾯\"' @ 1:1-11"
|
||||
- "'\"ૺ\"' @ 1:1-10"
|
||||
- "'\"¯\"' @ 1:1-9"
|
||||
- "'\"\n\"' @ 1:1-8"
|
||||
- "'\"\n\"' @ 1:1-7"
|
||||
- "'\"aa \\ \" \n aa \t \r \u0000\"' @ 1:1-28"
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- " --> test:1:1\n |\n 1 | ``\n | ^\n |\n = unexpected token: '`'"
|
||||
- " --> test:1:1\n |\n 1 | `Hello world!\n | ^\n |\n = unexpected token: '`'"
|
@ -0,0 +1,151 @@
|
||||
---
|
||||
namespace: ParseExpression
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- Value:
|
||||
String:
|
||||
- - s
|
||||
- t
|
||||
- r
|
||||
- i
|
||||
- n
|
||||
- g
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 9
|
||||
path: test
|
||||
content: "`string`"
|
||||
- Value:
|
||||
String:
|
||||
- - a
|
||||
- n
|
||||
- o
|
||||
- t
|
||||
- h
|
||||
- e
|
||||
- r
|
||||
- " "
|
||||
- "{"
|
||||
- " "
|
||||
- "}"
|
||||
- " "
|
||||
- s
|
||||
- t
|
||||
- r
|
||||
- i
|
||||
- n
|
||||
- g
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 21
|
||||
path: test
|
||||
content: "`another { } string`"
|
||||
- Value:
|
||||
String:
|
||||
- - "{"
|
||||
- " "
|
||||
- "]"
|
||||
- " "
|
||||
- "["
|
||||
- " "
|
||||
- ;
|
||||
- " "
|
||||
- a
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 12
|
||||
path: test
|
||||
content: "`{ ] [ ; a`"
|
||||
- Value:
|
||||
String:
|
||||
- -
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 10
|
||||
path: test
|
||||
content: "`\\u{FFA}`"
|
||||
- Value:
|
||||
String:
|
||||
- -
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 12
|
||||
path: test
|
||||
content: "`\\u{afafa}`"
|
||||
- Value:
|
||||
String:
|
||||
- - 꾯
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 11
|
||||
path: test
|
||||
content: "`\\u{afaf}`"
|
||||
- Value:
|
||||
String:
|
||||
- - ૺ
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 10
|
||||
path: test
|
||||
content: "`\\u{afa}`"
|
||||
- Value:
|
||||
String:
|
||||
- - ¯
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 9
|
||||
path: test
|
||||
content: "`\\u{af}`"
|
||||
- Value:
|
||||
String:
|
||||
- - "\n"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 8
|
||||
path: test
|
||||
content: "`\\u{a}`"
|
||||
- Value:
|
||||
String:
|
||||
- - "\n"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 7
|
||||
path: test
|
||||
content: "`\\x0A`"
|
||||
- Value:
|
||||
String:
|
||||
- - a
|
||||
- a
|
||||
- " "
|
||||
- "\\"
|
||||
- " "
|
||||
- "\""
|
||||
- " "
|
||||
- " "
|
||||
- "\n"
|
||||
- " "
|
||||
- a
|
||||
- a
|
||||
- " "
|
||||
- "\t"
|
||||
- " "
|
||||
- "\r"
|
||||
- " "
|
||||
- " "
|
||||
- "\u0000"
|
||||
- line_start: 1
|
||||
line_stop: 1
|
||||
col_start: 1
|
||||
col_stop: 28
|
||||
path: test
|
||||
content: "`aa \\\\ \\\" \\n aa \\t \\r \\0`"
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
namespace: ParseExpression
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
|
21
tests/parser/expression/literal/string.leo
Normal file
21
tests/parser/expression/literal/string.leo
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
namespace: Token
|
||||
expectation: Pass
|
||||
*/
|
||||
|
||||
`string`
|
||||
|
||||
`another { } string`
|
||||
|
||||
`{ ] [ ; a`
|
||||
|
||||
`\u{FFA}`
|
||||
`\u{afafa}`
|
||||
`\u{afaf}`
|
||||
`\u{afa}`
|
||||
`\u{af}`
|
||||
`\u{a}`
|
||||
|
||||
`\x0A`
|
||||
|
||||
`aa \\ \" \n aa \t \r \0`
|
8
tests/parser/expression/literal/string_fail.leo
Normal file
8
tests/parser/expression/literal/string_fail.leo
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
namespace: Token
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
``
|
||||
|
||||
`Hello world!
|
Loading…
Reference in New Issue
Block a user