Skip to main content

leo_input/values/
char_types.rs

1// Copyright (C) 2019-2021 Aleo Systems Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use crate::{
18    ast::{span_into_string, Rule},
19    errors::InputParserError,
20};
21
22use pest::Span;
23use pest_ast::FromPest;
24
25#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
26#[pest_ast(rule(Rule::basic_char))]
27pub struct BasicChar<'ast> {
28    #[pest_ast(outer(with(span_into_string)))]
29    pub value: String,
30    #[pest_ast(outer())]
31    pub span: Span<'ast>,
32}
33
34#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
35#[pest_ast(rule(Rule::escaped_char))]
36pub struct EscapedChar<'ast> {
37    #[pest_ast(outer(with(span_into_string)))]
38    pub value: String,
39    #[pest_ast(outer())]
40    pub span: Span<'ast>,
41}
42
43#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
44#[pest_ast(rule(Rule::hex_char))]
45pub struct HexChar<'ast> {
46    #[pest_ast(outer(with(span_into_string)))]
47    pub value: String,
48    #[pest_ast(outer())]
49    pub span: Span<'ast>,
50}
51
52#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
53#[pest_ast(rule(Rule::unicode_char))]
54pub struct UnicodeChar<'ast> {
55    #[pest_ast(outer(with(span_into_string)))]
56    pub value: String,
57    #[pest_ast(outer())]
58    pub span: Span<'ast>,
59}
60
61#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
62#[pest_ast(rule(Rule::char_types))]
63pub enum CharTypes<'ast> {
64    Basic(BasicChar<'ast>),
65    Escaped(EscapedChar<'ast>),
66    Hex(HexChar<'ast>),
67    Unicode(UnicodeChar<'ast>),
68}
69
70impl<'ast> CharTypes<'ast> {
71    pub fn span(&self) -> &Span<'ast> {
72        match self {
73            CharTypes::Basic(value) => &value.span,
74            CharTypes::Escaped(value) => &value.span,
75            CharTypes::Hex(value) => &value.span,
76            CharTypes::Unicode(value) => &value.span,
77        }
78    }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub enum Char {
83    Scalar(char),
84    NonScalar(u32),
85}
86
87impl<'ast> CharTypes<'ast> {
88    pub fn inner(self) -> Result<Char, InputParserError> {
89        match self {
90            Self::Basic(character) => {
91                if let Some(character) = character.value.chars().next() {
92                    return Ok(Char::Scalar(character));
93                }
94
95                Err(InputParserError::invalid_char(character.value, &character.span))
96            }
97            Self::Escaped(character) => {
98                if let Some(inner) = character.value.chars().nth(1) {
99                    return match inner {
100                        '0' => Ok(Char::Scalar(0 as char)),
101                        't' => Ok(Char::Scalar(9 as char)),
102                        'n' => Ok(Char::Scalar(10 as char)),
103                        'r' => Ok(Char::Scalar(13 as char)),
104                        '\"' => Ok(Char::Scalar(34 as char)),
105                        '\'' => Ok(Char::Scalar(39 as char)),
106                        '\\' => Ok(Char::Scalar(92 as char)),
107                        _ => Err(InputParserError::invalid_char(character.value, &character.span)),
108                    };
109                }
110
111                Err(InputParserError::invalid_char(character.value, &character.span))
112            }
113            Self::Hex(character) => {
114                let hex_string_number = character.value[2..character.value.len()].to_string();
115                if let Ok(number) = u8::from_str_radix(&hex_string_number, 16) {
116                    if number <= 127 {
117                        return Ok(Char::Scalar(number as char));
118                    }
119                }
120
121                Err(InputParserError::invalid_char(character.value, &character.span))
122            }
123            Self::Unicode(character) => {
124                let unicode_string_number = character.value[3..=character.value.len() - 2].to_string();
125                if let Ok(hex) = u32::from_str_radix(&unicode_string_number, 16) {
126                    if let Some(unicode) = std::char::from_u32(hex) {
127                        return Ok(Char::Scalar(unicode));
128                    } else if hex <= 0x10FFFF {
129                        return Ok(Char::NonScalar(hex));
130                    }
131                }
132
133                Err(InputParserError::invalid_char(character.value, &character.span))
134            }
135        }
136    }
137}