input string syntax

This commit is contained in:
gluax 2021-05-22 17:57:05 -04:00
parent 8cb1dc6e30
commit 1c57eb4196
22 changed files with 470 additions and 16 deletions

View File

@ -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`.
///

View File

@ -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);

View File

@ -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

View File

@ -25,3 +25,6 @@ pub use expression::*;
pub mod tuple_expression;
pub use tuple_expression::*;
pub mod string_expression;
pub use string_expression::*;

View File

@ -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, "\"")
}
}

View File

@ -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)+ ~")" }

View File

@ -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);

View File

@ -239,7 +239,7 @@ impl Token {
}
}
if !end {
if i == input.len() || i == 1 || !end {
return (0, None);
}

View File

@ -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!`;
}

View File

@ -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 {

View File

@ -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;

View File

@ -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!";

View File

@ -0,0 +1,6 @@
[main]
s1: [char; 13] = "\"ello, World\"";
s2: [char; 4] = "\u{2764}\x2A\x09\u{2764}";
[registers]
out: bool = true;

View File

@ -1,5 +1,5 @@
---
namespace: ParseExpression
namespace: Token
expectation: Fail
outputs:
- " --> test:1:1\n |\n 1 | '\\'\n | ^\n |\n = unexpected token: '''"

View File

@ -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`"

View File

@ -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"

View File

@ -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: '`'"

View File

@ -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`"

View File

@ -1,5 +1,5 @@
/*
namespace: ParseExpression
namespace: Token
expectation: Fail
*/

View 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`

View File

@ -0,0 +1,8 @@
/*
namespace: Token
expectation: Fail
*/
``
`Hello world!