1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! This crate provides a type `Value` that represents a [Python literal].
//! `Value` can be parsed from a string and formatted as a string.
//!
//! [Python literal]: https://docs.python.org/3/reference/lexical_analysis.html#literals
//!
//! # Example
//!
//! ```
//! extern crate num;
//! extern crate py_literal;
//!
//! use num::{BigInt, Complex};
//! use py_literal::Value;
//!
//! # fn example() -> Result<(), py_literal::ParseError> {
//! // Parse a literal value from a string.
//! let value: Value = "{ 'foo': [5, (7e3,)], 2 - 5j: {b'bar'} }".parse()?;
//! assert_eq!(
//!     value,
//!     Value::Dict(vec![
//!         (
//!             Value::String("foo".to_string()),
//!             Value::List(vec![
//!                 Value::Integer(BigInt::from(5)),
//!                 Value::Tuple(vec![Value::Float(7e3)]),
//!             ]),
//!         ),
//!         (
//!             Value::Complex(Complex::new(2., -5.)),
//!             Value::Set(vec![Value::Bytes(b"bar".to_vec())]),
//!         ),
//!     ]),
//! );
//!
//! // Format a literal value as a string.
//! let formatted = format!("{}", value);
//! assert_eq!(
//!     formatted,
//!     "{'foo': [5, (7e3,)], 2-5j: {b'bar'}}",
//! );
//! # Ok(())
//! # }
//! # fn main() {
//! #     example().unwrap();
//! # }
//! ```

extern crate num;
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate quick_error;

mod format;
#[macro_use]
mod parse_macros;
mod parse;

pub use format::FormatError;
pub use parse::ParseError;

use num::{BigInt, Complex};
use std::fmt;

/// Python literal.
///
/// This type should be able to express everything that Python's
/// [`ast.literal_eval()`] can evaluate, except for operators. Similar to
/// `literal_eval()`, addition and subtraction of numbers is supported in the
/// parser. However, binary addition and subtraction operators cannot be
/// formatted using `Value`.
///
/// [`ast.literal_eval()`]: https://docs.python.org/3/library/ast.html#ast.literal_eval
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    /// Python string (`str`). When parsing, backslash escapes are interpreted.
    /// When formatting, backslash escapes are used to ensure the result is
    /// contains only ASCII chars.
    String(String),
    /// Python byte sequence (`bytes`). When parsing, backslash escapes are
    /// interpreted. When formatting, backslash escapes are used to ensure the
    /// result is contains only ASCII chars.
    Bytes(Vec<u8>),
    /// Python integer (`int`). Python integers have unlimited precision, so we
    /// use `BigInt`.
    Integer(BigInt),
    /// Python floating-point number (`float`). The representation and
    /// precision of the Python `float` type varies by the machine where the
    /// program is executing, but `f64` should be good enough.
    Float(f64),
    /// Python complex number (`complex`). The Python `complex` type contains
    /// two `float` values.
    Complex(Complex<f64>),
    /// Python tuple (`tuple`).
    Tuple(Vec<Value>),
    /// Python list (`list`).
    List(Vec<Value>),
    /// Python dictionary (`dict`).
    Dict(Vec<(Value, Value)>),
    /// Python set (`set`).
    Set(Vec<Value>),
    /// Python boolean (`bool`).
    Boolean(bool),
    /// Python `None`.
    None,
}

impl fmt::Display for Value {
    /// Formats the value as a Python literal.
    ///
    /// Currently, this just calls `self.format_ascii()`, but that may change
    /// in the future.
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        // TODO: is there a better way to do this?
        write!(f, "{}", self.format_ascii().map_err(|_| fmt::Error)?)
    }
}