just need to fix input file parsing for chars to work

This commit is contained in:
gluax 2021-05-12 18:56:27 -04:00
parent 602300ea64
commit 0ef7ca3d8e
23 changed files with 328 additions and 8 deletions

View File

@ -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_),

View File

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

View File

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

View 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)
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
function main() {
const a: char = 'a';
const B = 'B';
}

View File

@ -0,0 +1,7 @@
circuit Foo {
a: char;
}
function main() {
const f = Foo { a: 'a' };
}

View File

@ -0,0 +1,4 @@
function main() {
const newline: char = '\n';
const quote = '\'';
}

View File

@ -0,0 +1,7 @@
function b(a: char) -> char {
return a;
}
function main() {
const b = b('x');
}

View File

@ -0,0 +1,4 @@
function main() {
const heart: char = '\u{2764}';
const Hiragana = '\u{306E}';
}

View File

View File

@ -0,0 +1,3 @@
[main]
a: char = '\u{2764}';
b: char = 'a';

View File

@ -0,0 +1,2 @@
[registers]
r: char = '\n';

101
compiler/tests/char/mod.rs Normal file
View 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);
}

View File

@ -0,0 +1,2 @@
[registers]
r: char = '\n';

View File

@ -0,0 +1,3 @@
function main() -> char {
return input.registers.r;
}

View File

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

View File

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

View 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)
}
}

View File

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

View File

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