mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-25 18:42:26 +03:00
just need to fix input file parsing for chars to work
This commit is contained in:
parent
602300ea64
commit
0ef7ca3d8e
@ -19,7 +19,16 @@ use leo_input::{
|
||||
errors::InputParserError,
|
||||
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression, TupleExpression},
|
||||
types::{ArrayType, DataType, IntegerType, TupleType, Type},
|
||||
values::{Address, AddressValue, BooleanValue, FieldValue, GroupValue as InputGroupValue, NumberValue, Value},
|
||||
values::{
|
||||
Address,
|
||||
AddressValue,
|
||||
BooleanValue,
|
||||
CharValue,
|
||||
FieldValue,
|
||||
GroupValue as InputGroupValue,
|
||||
NumberValue,
|
||||
Value,
|
||||
},
|
||||
};
|
||||
use pest::Span;
|
||||
|
||||
@ -29,6 +38,7 @@ use std::fmt;
|
||||
pub enum InputValue {
|
||||
Address(String),
|
||||
Boolean(bool),
|
||||
Char(String),
|
||||
Field(String),
|
||||
Group(GroupValue),
|
||||
Integer(IntegerType, String),
|
||||
@ -53,6 +63,10 @@ impl InputValue {
|
||||
Ok(InputValue::Boolean(boolean))
|
||||
}
|
||||
|
||||
fn from_char(character: CharValue) -> Self {
|
||||
InputValue::Char(character.value)
|
||||
}
|
||||
|
||||
fn from_number(integer_type: IntegerType, number: String) -> Self {
|
||||
InputValue::Integer(integer_type, number)
|
||||
}
|
||||
@ -80,6 +94,7 @@ impl InputValue {
|
||||
match (data_type, value) {
|
||||
(DataType::Address(_), Value::Address(address)) => Ok(InputValue::from_address_value(address)),
|
||||
(DataType::Boolean(_), Value::Boolean(boolean)) => InputValue::from_boolean(boolean),
|
||||
(DataType::Char(_), Value::Char(character)) => Ok(InputValue::from_char(character)),
|
||||
(DataType::Integer(integer_type), Value::Integer(integer)) => {
|
||||
Ok(InputValue::from_number(integer_type, integer.to_string()))
|
||||
}
|
||||
@ -304,6 +319,7 @@ impl fmt::Display for InputValue {
|
||||
match self {
|
||||
InputValue::Address(ref address) => write!(f, "{}", address),
|
||||
InputValue::Boolean(ref boolean) => write!(f, "{}", boolean),
|
||||
InputValue::Char(ref character) => write!(f, "{}", character),
|
||||
InputValue::Group(ref group) => write!(f, "{}", group),
|
||||
InputValue::Field(ref field) => write!(f, "{}", field),
|
||||
InputValue::Integer(ref type_, ref number) => write!(f, "{}{:?}", number, type_),
|
||||
|
@ -14,7 +14,16 @@
|
||||
// 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::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
|
||||
use crate::errors::{
|
||||
AddressError,
|
||||
BooleanError,
|
||||
CharError,
|
||||
FieldError,
|
||||
FunctionError,
|
||||
GroupError,
|
||||
IntegerError,
|
||||
ValueError,
|
||||
};
|
||||
use leo_ast::{FormattedError, Identifier, LeoError, Span};
|
||||
use snarkvm_r1cs::SynthesisError;
|
||||
|
||||
@ -26,6 +35,9 @@ pub enum ExpressionError {
|
||||
#[error("{}", _0)]
|
||||
BooleanError(#[from] BooleanError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
CharError(#[from] CharError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
use crate::errors::{
|
||||
AddressError,
|
||||
BooleanError,
|
||||
CharError,
|
||||
ExpressionError,
|
||||
FieldError,
|
||||
GroupError,
|
||||
@ -36,6 +37,9 @@ pub enum FunctionError {
|
||||
#[error("{}", _0)]
|
||||
BooleanError(#[from] BooleanError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
CharError(#[from] CharError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ExpressionError(#[from] ExpressionError),
|
||||
|
||||
|
41
compiler/src/errors/value/char.rs
Normal file
41
compiler/src/errors/value/char.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2019-2021 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/>.
|
||||
|
||||
use crate::errors::FieldError;
|
||||
use leo_ast::{FormattedError, LeoError, Span};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CharError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
FieldError(#[from] FieldError),
|
||||
}
|
||||
|
||||
impl LeoError for CharError {}
|
||||
|
||||
impl CharError {
|
||||
fn new_from_span(message: String, span: &Span) -> Self {
|
||||
CharError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn invalid_char(actual: String, span: &Span) -> Self {
|
||||
let message = format!("expected char element input type, found `{}`", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
@ -20,6 +20,9 @@ pub use self::address::*;
|
||||
pub mod boolean;
|
||||
pub use self::boolean::*;
|
||||
|
||||
pub mod char;
|
||||
pub use self::char::*;
|
||||
|
||||
pub mod field;
|
||||
pub use self::field::*;
|
||||
|
||||
|
@ -18,14 +18,16 @@
|
||||
|
||||
use crate::{
|
||||
address::Address,
|
||||
errors::FunctionError,
|
||||
errors::{CharError, FunctionError},
|
||||
program::ConstrainedProgram,
|
||||
value::{
|
||||
boolean::input::bool_from_input,
|
||||
char::char_from_input,
|
||||
field::input::field_from_input,
|
||||
group::input::group_from_input,
|
||||
ConstrainedValue,
|
||||
},
|
||||
Char,
|
||||
FieldType,
|
||||
GroupType,
|
||||
Integer,
|
||||
@ -49,6 +51,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
match type_ {
|
||||
Type::Address => Ok(Address::from_input(cs, name, input_option, span)?),
|
||||
Type::Boolean => Ok(bool_from_input(cs, name, input_option, span)?),
|
||||
Type::Char => Ok(char_from_input(cs, name, input_option, span)?),
|
||||
Type::Field => Ok(field_from_input(cs, name, input_option, span)?),
|
||||
Type::Group => Ok(group_from_input(cs, name, input_option, span)?),
|
||||
Type::Integer(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input(
|
||||
@ -80,6 +83,17 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
match (type_, input) {
|
||||
(Type::Address, InputValue::Address(addr)) => Ok(ConstrainedValue::Address(Address::constant(addr, span)?)),
|
||||
(Type::Boolean, InputValue::Boolean(value)) => Ok(ConstrainedValue::Boolean(Boolean::constant(value))),
|
||||
(Type::Char, InputValue::Char(value)) => {
|
||||
if let Some(character) = value.chars().nth(1) {
|
||||
Ok(ConstrainedValue::Char(Char::constant(
|
||||
character,
|
||||
format!("{}", character as u32),
|
||||
span,
|
||||
)?))
|
||||
} else {
|
||||
Err(FunctionError::from(CharError::invalid_char(value, span)))
|
||||
}
|
||||
}
|
||||
(Type::Field, InputValue::Field(value)) => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
|
||||
(Type::Group, InputValue::Group(value)) => Ok(ConstrainedValue::Group(G::constant(&value.into(), span)?)),
|
||||
(Type::Integer(integer_type), InputValue::Integer(_, value)) => Ok(ConstrainedValue::Integer(
|
||||
|
@ -14,9 +14,16 @@
|
||||
// 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::{errors::FieldError, FieldType};
|
||||
use leo_ast::Span;
|
||||
use crate::{
|
||||
errors::CharError,
|
||||
value::{field::input::allocate_field, ConstrainedValue},
|
||||
FieldType,
|
||||
GroupType,
|
||||
};
|
||||
|
||||
use leo_ast::{InputValue, Span};
|
||||
use snarkvm_fields::PrimeField;
|
||||
use snarkvm_r1cs::ConstraintSystem;
|
||||
|
||||
/// A char
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -26,7 +33,7 @@ pub struct Char<F: PrimeField> {
|
||||
}
|
||||
|
||||
impl<F: PrimeField> Char<F> {
|
||||
pub fn constant(character: char, field: String, span: &Span) -> Result<Self, FieldError> {
|
||||
pub fn constant(character: char, field: String, span: &Span) -> Result<Self, CharError> {
|
||||
Ok(Self {
|
||||
character,
|
||||
field: FieldType::constant(field, span)?,
|
||||
@ -34,6 +41,36 @@ impl<F: PrimeField> Char<F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn char_from_input<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
name: &str,
|
||||
input_value: Option<InputValue>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<'a, F, G>, CharError> {
|
||||
// Check that the parameter value is the correct type
|
||||
let option = match input_value {
|
||||
Some(input) => {
|
||||
if let InputValue::Char(string) = input {
|
||||
if let Some(character) = string.chars().nth(1) {
|
||||
(character, Some((character as u32).to_string()))
|
||||
} else {
|
||||
return Err(CharError::invalid_char(string, span));
|
||||
}
|
||||
} else {
|
||||
return Err(CharError::invalid_char(input.to_string(), span));
|
||||
}
|
||||
}
|
||||
None => (' ', None),
|
||||
};
|
||||
|
||||
let field = allocate_field(cs, name, option.1, span)?;
|
||||
|
||||
Ok(ConstrainedValue::Char(Char {
|
||||
character: option.0,
|
||||
field,
|
||||
}))
|
||||
}
|
||||
|
||||
impl<F: PrimeField + std::fmt::Display> std::fmt::Display for Char<F> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.character)
|
||||
|
4
compiler/tests/char/basic.leo
Normal file
4
compiler/tests/char/basic.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
const a: char = 'a';
|
||||
const B = 'B';
|
||||
}
|
7
compiler/tests/char/circuit.leo
Normal file
7
compiler/tests/char/circuit.leo
Normal file
@ -0,0 +1,7 @@
|
||||
circuit Foo {
|
||||
a: char;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const f = Foo { a: 'a' };
|
||||
}
|
4
compiler/tests/char/escapes.leo
Normal file
4
compiler/tests/char/escapes.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
const newline: char = '\n';
|
||||
const quote = '\'';
|
||||
}
|
7
compiler/tests/char/function.leo
Normal file
7
compiler/tests/char/function.leo
Normal file
@ -0,0 +1,7 @@
|
||||
function b(a: char) -> char {
|
||||
return a;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const b = b('x');
|
||||
}
|
4
compiler/tests/char/hex.leo
Normal file
4
compiler/tests/char/hex.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
const heart: char = '\u{2764}';
|
||||
const Hiragana = '\u{306E}';
|
||||
}
|
0
compiler/tests/char/input.leo
Normal file
0
compiler/tests/char/input.leo
Normal file
3
compiler/tests/char/input/char.in
Normal file
3
compiler/tests/char/input/char.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
a: char = '\u{2764}';
|
||||
b: char = 'a';
|
2
compiler/tests/char/input/char_register.in
Normal file
2
compiler/tests/char/input/char_register.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: char = '\n';
|
101
compiler/tests/char/mod.rs
Normal file
101
compiler/tests/char/mod.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2019-2021 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/>.
|
||||
|
||||
use crate::{
|
||||
assert_satisfied,
|
||||
get_output,
|
||||
parse_program,
|
||||
parse_program_with_input,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
|
||||
pub fn output_char(program: EdwardsTestCompiler) {
|
||||
let expected = include_bytes!("output/output_char.out");
|
||||
let actual = get_output(program);
|
||||
|
||||
assert_eq!(expected, actual.bytes().as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_pass() {
|
||||
let program_string = include_str!("input.leo");
|
||||
let input_string = include_str!("input/char.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_input_fail() {
|
||||
// let program_string = include_str!("assert_eq_input.leo");
|
||||
// let input_string = include_str!("input/true_false.in");
|
||||
|
||||
// let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
// expect_compiler_error(program);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_registers() {
|
||||
let program_string = include_str!("output_register.leo");
|
||||
let char_input_string = include_str!("input/char_register.in");
|
||||
|
||||
// test true input register => true output register
|
||||
let program = parse_program_with_input(program_string, char_input_string).unwrap();
|
||||
|
||||
output_char(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let program_string = include_str!("basic.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escapes() {
|
||||
let program_string = include_str!("escapes.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex() {
|
||||
let program_string = include_str!("hex.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function() {
|
||||
let program_string = include_str!("function.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit() {
|
||||
let program_string = include_str!("function.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
2
compiler/tests/char/output/output_char.out
Normal file
2
compiler/tests/char/output/output_char.out
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: char = '\n';
|
3
compiler/tests/char/output_register.leo
Normal file
3
compiler/tests/char/output_register.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() -> char {
|
||||
return input.registers.r;
|
||||
}
|
@ -22,6 +22,7 @@ pub mod address;
|
||||
pub mod array;
|
||||
pub mod boolean;
|
||||
pub mod canonicalization;
|
||||
pub mod char;
|
||||
pub mod circuits;
|
||||
pub mod compiler;
|
||||
pub mod console;
|
||||
|
@ -9,6 +9,7 @@ protected_name = {
|
||||
| "else"
|
||||
| "false"
|
||||
| type_field
|
||||
| type_char
|
||||
| "for"
|
||||
| "function"
|
||||
| type_group
|
||||
@ -89,7 +90,7 @@ type_boolean = { "bool" }
|
||||
type_address = { "address" }
|
||||
|
||||
// Declared in types/data_type.rs
|
||||
type_data = { type_field | type_group | type_boolean | type_address | type_integer }
|
||||
type_data = { type_field | type_group | type_boolean | type_address | type_integer | type_char }
|
||||
|
||||
// Declared in types/array_type.rs
|
||||
type_array = { "[" ~ type_ ~ ";" ~ array_dimensions ~ "]" }
|
||||
@ -118,6 +119,7 @@ value = {
|
||||
| value_boolean
|
||||
| value_field
|
||||
| value_group
|
||||
| value_char
|
||||
| value_integer
|
||||
| value_number // must be last as a catch all
|
||||
}
|
||||
@ -132,6 +134,17 @@ number_negative = @{ "-" ~ ASCII_DIGIT+ }
|
||||
number_positive = @{ ASCII_DIGIT+ }
|
||||
|
||||
|
||||
|
||||
// Declared in values/char_value.rs
|
||||
// ANY is equivalent to '\u{00}'..'\u{10FFFF}'
|
||||
// TODO FIX
|
||||
// value_char = {
|
||||
// !("\'" | "\\") ~ ANY
|
||||
// | "\\" ~ ("\"" | "\'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
|
||||
// | "\\" ~ ("u" ~ ASCII_HEX_DIGIT(4))
|
||||
// }
|
||||
value_char = { "'" ~ "\\"? ~ ANY ~ "'" }
|
||||
|
||||
// Declared in values/integer_value.rs
|
||||
value_integer = { value_integer_signed | value_integer_unsigned}
|
||||
|
||||
|
36
input/src/values/char_value.rs
Normal file
36
input/src/values/char_value.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2019-2021 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/>.
|
||||
|
||||
use crate::ast::{span_into_string, Rule};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
|
||||
#[pest_ast(rule(Rule::value_char))]
|
||||
pub struct CharValue<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub value: String,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for CharValue<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
@ -26,6 +26,9 @@ pub use address_value::*;
|
||||
pub mod boolean_value;
|
||||
pub use boolean_value::*;
|
||||
|
||||
pub mod char_value;
|
||||
pub use char_value::*;
|
||||
|
||||
pub mod field_value;
|
||||
pub use field_value::*;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
values::{BooleanValue, FieldValue, GroupValue, IntegerValue, NumberValue},
|
||||
values::{BooleanValue, CharValue, FieldValue, GroupValue, IntegerValue, NumberValue},
|
||||
};
|
||||
|
||||
use crate::values::AddressValue;
|
||||
@ -29,6 +29,7 @@ use std::fmt;
|
||||
pub enum Value<'ast> {
|
||||
Address(AddressValue<'ast>),
|
||||
Boolean(BooleanValue<'ast>),
|
||||
Char(CharValue<'ast>),
|
||||
Field(FieldValue<'ast>),
|
||||
Group(GroupValue<'ast>),
|
||||
Implicit(NumberValue<'ast>),
|
||||
@ -40,6 +41,7 @@ impl<'ast> Value<'ast> {
|
||||
match self {
|
||||
Value::Address(value) => &value.span(),
|
||||
Value::Boolean(value) => &value.span,
|
||||
Value::Char(value) => &value.span,
|
||||
Value::Field(value) => &value.span,
|
||||
Value::Group(value) => &value.span,
|
||||
Value::Implicit(value) => &value.span(),
|
||||
@ -53,6 +55,7 @@ impl<'ast> fmt::Display for Value<'ast> {
|
||||
match *self {
|
||||
Value::Address(ref value) => write!(f, "{}", value),
|
||||
Value::Boolean(ref value) => write!(f, "{}", value),
|
||||
Value::Char(ref value) => write!(f, "{}", value),
|
||||
Value::Field(ref value) => write!(f, "{}", value),
|
||||
Value::Group(ref value) => write!(f, "{}", value),
|
||||
Value::Implicit(ref value) => write!(f, "{}", value),
|
||||
|
Loading…
Reference in New Issue
Block a user