mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 19:57:44 +02:00
Remove old nushell/merge engine-q
This commit is contained in:
@ -1,17 +1,10 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors", "Christian Zangl <laktak@cdak.net>"]
|
||||
description = "Fork of serde-hjson"
|
||||
<<<<<<< HEAD
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-json"
|
||||
version = "0.43.0"
|
||||
=======
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-json"
|
||||
version = "0.37.1"
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
version = "0.59.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -27,10 +20,5 @@ lazy_static = "1"
|
||||
linked-hash-map = { version="0.5", optional=true }
|
||||
|
||||
[dev-dependencies]
|
||||
<<<<<<< HEAD
|
||||
nu-path = { version = "0.43.0", path="../nu-path" }
|
||||
nu-test-support = { version = "0.43.0", path="../nu-test-support" }
|
||||
=======
|
||||
nu-path = { version = "0.37.1", path="../nu-path" }
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
nu-path = { path="../nu-path", version = "0.59.0" }
|
||||
serde_json = "1.0.39"
|
||||
|
29
crates/nu-json/LICENSE
Normal file
29
crates/nu-json/LICENSE
Normal file
@ -0,0 +1,29 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
Copyright (c) 2016 Christian Zangl
|
||||
Copyright (c) 2020 The Nu Project Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
115
crates/nu-json/src/builder.rs
Normal file
115
crates/nu-json/src/builder.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use serde::ser;
|
||||
|
||||
use crate::value::{self, Map, Value};
|
||||
|
||||
/// This structure provides a simple interface for constructing a JSON array.
|
||||
pub struct ArrayBuilder {
|
||||
array: Vec<Value>,
|
||||
}
|
||||
|
||||
impl Default for ArrayBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ArrayBuilder {
|
||||
/// Construct an `ObjectBuilder`.
|
||||
pub fn new() -> ArrayBuilder {
|
||||
ArrayBuilder { array: Vec::new() }
|
||||
}
|
||||
|
||||
/// Return the constructed `Value`.
|
||||
pub fn unwrap(self) -> Value {
|
||||
Value::Array(self.array)
|
||||
}
|
||||
|
||||
/// Insert a value into the array.
|
||||
pub fn push<T: ser::Serialize>(mut self, v: T) -> ArrayBuilder {
|
||||
self.array
|
||||
.push(value::to_value(&v).expect("failed to serialize"));
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and passes an `ArrayBuilder` into a closure, then inserts the resulting array into
|
||||
/// this array.
|
||||
pub fn push_array<F>(mut self, f: F) -> ArrayBuilder
|
||||
where
|
||||
F: FnOnce(ArrayBuilder) -> ArrayBuilder,
|
||||
{
|
||||
let builder = ArrayBuilder::new();
|
||||
self.array.push(f(builder).unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and passes an `ArrayBuilder` into a closure, then inserts the resulting object into
|
||||
/// this array.
|
||||
pub fn push_object<F>(mut self, f: F) -> ArrayBuilder
|
||||
where
|
||||
F: FnOnce(ObjectBuilder) -> ObjectBuilder,
|
||||
{
|
||||
let builder = ObjectBuilder::new();
|
||||
self.array.push(f(builder).unwrap());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// This structure provides a simple interface for constructing a JSON object.
|
||||
pub struct ObjectBuilder {
|
||||
object: Map<String, Value>,
|
||||
}
|
||||
|
||||
impl Default for ObjectBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectBuilder {
|
||||
/// Construct an `ObjectBuilder`.
|
||||
pub fn new() -> ObjectBuilder {
|
||||
ObjectBuilder { object: Map::new() }
|
||||
}
|
||||
|
||||
/// Return the constructed `Value`.
|
||||
pub fn unwrap(self) -> Value {
|
||||
Value::Object(self.object)
|
||||
}
|
||||
|
||||
/// Insert a key-value pair into the object.
|
||||
pub fn insert<S, V>(mut self, key: S, value: V) -> ObjectBuilder
|
||||
where
|
||||
S: Into<String>,
|
||||
V: ser::Serialize,
|
||||
{
|
||||
self.object.insert(
|
||||
key.into(),
|
||||
value::to_value(&value).expect("failed to serialize"),
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and passes an `ObjectBuilder` into a closure, then inserts the resulting array into
|
||||
/// this object.
|
||||
pub fn insert_array<S, F>(mut self, key: S, f: F) -> ObjectBuilder
|
||||
where
|
||||
S: Into<String>,
|
||||
F: FnOnce(ArrayBuilder) -> ArrayBuilder,
|
||||
{
|
||||
let builder = ArrayBuilder::new();
|
||||
self.object.insert(key.into(), f(builder).unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates and passes an `ObjectBuilder` into a closure, then inserts the resulting object into
|
||||
/// this object.
|
||||
pub fn insert_object<S, F>(mut self, key: S, f: F) -> ObjectBuilder
|
||||
where
|
||||
S: Into<String>,
|
||||
F: FnOnce(ObjectBuilder) -> ObjectBuilder,
|
||||
{
|
||||
let builder = ObjectBuilder::new();
|
||||
self.object.insert(key.into(), f(builder).unwrap());
|
||||
self
|
||||
}
|
||||
}
|
833
crates/nu-json/src/de.rs
Normal file
833
crates/nu-json/src/de.rs
Normal file
@ -0,0 +1,833 @@
|
||||
//! Hjson Deserialization
|
||||
//!
|
||||
//! This module provides for Hjson deserialization with the type `Deserializer`.
|
||||
|
||||
use std::char;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::str;
|
||||
|
||||
use serde::de;
|
||||
|
||||
use super::error::{Error, ErrorCode, Result};
|
||||
use super::util::StringReader;
|
||||
use super::util::{Number, ParseNumber};
|
||||
|
||||
enum State {
|
||||
Normal,
|
||||
Root,
|
||||
Keyname,
|
||||
}
|
||||
|
||||
/// A structure that deserializes Hjson into Rust values.
|
||||
pub struct Deserializer<Iter: Iterator<Item = u8>> {
|
||||
rdr: StringReader<Iter>,
|
||||
str_buf: Vec<u8>,
|
||||
state: State,
|
||||
}
|
||||
|
||||
// macro_rules! try_or_invalid {
|
||||
// ($self_:expr, $e:expr) => {
|
||||
// match $e {
|
||||
// Some(v) => v,
|
||||
// None => { return Err($self_.error(ErrorCode::InvalidNumber)); }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<Iter> Deserializer<Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
/// Creates the Hjson parser from an `std::iter::Iterator`.
|
||||
#[inline]
|
||||
pub fn new(rdr: Iter) -> Deserializer<Iter> {
|
||||
Deserializer {
|
||||
rdr: StringReader::new(rdr),
|
||||
str_buf: Vec::with_capacity(128),
|
||||
state: State::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the Hjson parser from an `std::iter::Iterator`.
|
||||
#[inline]
|
||||
pub fn new_for_root(rdr: Iter) -> Deserializer<Iter> {
|
||||
let mut res = Deserializer::new(rdr);
|
||||
res.state = State::Root;
|
||||
res
|
||||
}
|
||||
|
||||
/// The `Deserializer::end` method should be called after a value has been fully deserialized.
|
||||
/// This allows the `Deserializer` to validate that the input stream is at the end or that it
|
||||
/// only has trailing whitespace.
|
||||
#[inline]
|
||||
pub fn end(&mut self) -> Result<()> {
|
||||
self.rdr.parse_whitespace()?;
|
||||
if self.rdr.eof()? {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(self.rdr.error(ErrorCode::TrailingCharacters))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_punctuator_char(&mut self, ch: u8) -> bool {
|
||||
matches!(ch, b'{' | b'}' | b'[' | b']' | b',' | b':')
|
||||
}
|
||||
|
||||
fn parse_keyname<'de, V>(&mut self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
// quotes for keys are optional in Hjson
|
||||
// unless they include {}[],: or whitespace.
|
||||
// assume whitespace was already eaten
|
||||
|
||||
self.str_buf.clear();
|
||||
|
||||
let mut space: Option<usize> = None;
|
||||
loop {
|
||||
let ch = self.rdr.next_char_or_null()?;
|
||||
|
||||
if ch == b':' {
|
||||
if self.str_buf.is_empty() {
|
||||
return Err(self.rdr.error(ErrorCode::Custom(
|
||||
"Found ':' but no key name (for an empty key name use quotes)".to_string(),
|
||||
)));
|
||||
} else if space.is_some()
|
||||
&& space.expect("Internal error: json parsing") != self.str_buf.len()
|
||||
{
|
||||
return Err(self.rdr.error(ErrorCode::Custom(
|
||||
"Found whitespace in your key name (use quotes to include)".to_string(),
|
||||
)));
|
||||
}
|
||||
self.rdr.uneat_char(ch);
|
||||
let s = str::from_utf8(&self.str_buf).expect("Internal error: json parsing");
|
||||
return visitor.visit_str(s);
|
||||
} else if ch <= b' ' {
|
||||
if ch == 0 {
|
||||
return Err(self.rdr.error(ErrorCode::EofWhileParsingObject));
|
||||
} else if space.is_none() {
|
||||
space = Some(self.str_buf.len());
|
||||
}
|
||||
} else if self.is_punctuator_char(ch) {
|
||||
return Err(self.rdr.error(ErrorCode::Custom("Found a punctuator where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)".to_string())));
|
||||
} else {
|
||||
self.str_buf.push(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_value<'de, V>(&mut self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.rdr.parse_whitespace()?;
|
||||
|
||||
if self.rdr.eof()? {
|
||||
return Err(self.rdr.error(ErrorCode::EofWhileParsingValue));
|
||||
}
|
||||
|
||||
match self.state {
|
||||
State::Keyname => {
|
||||
self.state = State::Normal;
|
||||
return self.parse_keyname(visitor);
|
||||
}
|
||||
State::Root => {
|
||||
self.state = State::Normal;
|
||||
return self.visit_map(true, visitor);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.rdr.peek_or_null()? {
|
||||
/*
|
||||
b'-' => {
|
||||
self.rdr.eat_char();
|
||||
self.parse_integer(false, visitor)
|
||||
}
|
||||
b'0' ... b'9' => {
|
||||
self.parse_integer(true, visitor)
|
||||
}
|
||||
*/
|
||||
b'"' => {
|
||||
self.rdr.eat_char();
|
||||
self.parse_string()?;
|
||||
let s = str::from_utf8(&self.str_buf).expect("Internal error: json parsing");
|
||||
visitor.visit_str(s)
|
||||
}
|
||||
b'[' => {
|
||||
self.rdr.eat_char();
|
||||
let ret = visitor.visit_seq(SeqVisitor::new(self))?;
|
||||
self.rdr.parse_whitespace()?;
|
||||
match self.rdr.next_char()? {
|
||||
Some(b']') => Ok(ret),
|
||||
Some(_) => Err(self.rdr.error(ErrorCode::TrailingCharacters)),
|
||||
None => Err(self.rdr.error(ErrorCode::EofWhileParsingList)),
|
||||
}
|
||||
}
|
||||
b'{' => {
|
||||
self.rdr.eat_char();
|
||||
self.visit_map(false, visitor)
|
||||
}
|
||||
b'\x00' => Err(self.rdr.error(ErrorCode::ExpectedSomeValue)),
|
||||
_ => self.parse_tfnns(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_map<'de, V>(&mut self, root: bool, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let ret = visitor.visit_map(MapVisitor::new(self, root))?;
|
||||
self.rdr.parse_whitespace()?;
|
||||
match self.rdr.next_char()? {
|
||||
Some(b'}') => {
|
||||
if !root {
|
||||
Ok(ret)
|
||||
} else {
|
||||
Err(self.rdr.error(ErrorCode::TrailingCharacters))
|
||||
} // todo
|
||||
}
|
||||
Some(_) => Err(self.rdr.error(ErrorCode::TrailingCharacters)),
|
||||
None => {
|
||||
if root {
|
||||
Ok(ret)
|
||||
} else {
|
||||
Err(self.rdr.error(ErrorCode::EofWhileParsingObject))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ident(&mut self, ident: &[u8]) -> Result<()> {
|
||||
for c in ident {
|
||||
if Some(*c) != self.rdr.next_char()? {
|
||||
return Err(self.rdr.error(ErrorCode::ExpectedSomeIdent));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_tfnns<'de, V>(&mut self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
// Hjson strings can be quoteless
|
||||
// returns string, true, false, or null.
|
||||
self.str_buf.clear();
|
||||
|
||||
let first = self.rdr.peek()?.expect("Internal error: json parsing");
|
||||
|
||||
if self.is_punctuator_char(first) {
|
||||
return Err(self.rdr.error(ErrorCode::PunctuatorInQlString));
|
||||
}
|
||||
|
||||
loop {
|
||||
let ch = self.rdr.next_char_or_null()?;
|
||||
|
||||
let is_eol = ch == b'\r' || ch == b'\n' || ch == b'\x00';
|
||||
let is_comment = ch == b'#'
|
||||
|| if ch == b'/' {
|
||||
let next = self.rdr.peek_or_null()?;
|
||||
next == b'/' || next == b'*'
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if is_eol || is_comment || ch == b',' || ch == b'}' || ch == b']' {
|
||||
let chf = self.str_buf[0];
|
||||
match chf {
|
||||
b'f' => {
|
||||
if str::from_utf8(&self.str_buf)
|
||||
.expect("Internal error: json parsing")
|
||||
.trim()
|
||||
== "false"
|
||||
{
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_bool(false);
|
||||
}
|
||||
}
|
||||
b'n' => {
|
||||
if str::from_utf8(&self.str_buf)
|
||||
.expect("Internal error: json parsing")
|
||||
.trim()
|
||||
== "null"
|
||||
{
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_unit();
|
||||
}
|
||||
}
|
||||
b't' => {
|
||||
if str::from_utf8(&self.str_buf)
|
||||
.expect("Internal error: json parsing")
|
||||
.trim()
|
||||
== "true"
|
||||
{
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_bool(true);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if chf == b'-' || (b'0'..=b'9').contains(&chf) {
|
||||
let mut pn = ParseNumber::new(self.str_buf.iter().copied());
|
||||
match pn.parse(false) {
|
||||
Ok(Number::F64(v)) => {
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_f64(v);
|
||||
}
|
||||
Ok(Number::U64(v)) => {
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_u64(v);
|
||||
}
|
||||
Ok(Number::I64(v)) => {
|
||||
self.rdr.uneat_char(ch);
|
||||
return visitor.visit_i64(v);
|
||||
}
|
||||
Err(_) => {} // not a number, continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_eol {
|
||||
// remove any whitespace at the end (ignored in quoteless strings)
|
||||
return visitor.visit_str(
|
||||
str::from_utf8(&self.str_buf)
|
||||
.expect("Internal error: json parsing")
|
||||
.trim(),
|
||||
);
|
||||
}
|
||||
}
|
||||
self.str_buf.push(ch);
|
||||
|
||||
if self.str_buf == b"'''" {
|
||||
return self.parse_ml_string(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_hex_escape(&mut self) -> Result<u16> {
|
||||
let mut i = 0;
|
||||
let mut n = 0u16;
|
||||
while i < 4 && !self.rdr.eof()? {
|
||||
n = match self.rdr.next_char_or_null()? {
|
||||
c @ b'0'..=b'9' => n * 16_u16 + ((c as u16) - (b'0' as u16)),
|
||||
b'a' | b'A' => n * 16_u16 + 10_u16,
|
||||
b'b' | b'B' => n * 16_u16 + 11_u16,
|
||||
b'c' | b'C' => n * 16_u16 + 12_u16,
|
||||
b'd' | b'D' => n * 16_u16 + 13_u16,
|
||||
b'e' | b'E' => n * 16_u16 + 14_u16,
|
||||
b'f' | b'F' => n * 16_u16 + 15_u16,
|
||||
_ => {
|
||||
return Err(self.rdr.error(ErrorCode::InvalidEscape));
|
||||
}
|
||||
};
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Error out if we didn't parse 4 digits.
|
||||
if i != 4 {
|
||||
return Err(self.rdr.error(ErrorCode::InvalidEscape));
|
||||
}
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
fn ml_skip_white(&mut self) -> Result<bool> {
|
||||
match self.rdr.peek_or_null()? {
|
||||
b' ' | b'\t' | b'\r' => {
|
||||
self.rdr.eat_char();
|
||||
Ok(true)
|
||||
}
|
||||
_ => Ok(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn ml_skip_indent(&mut self, indent: usize) -> Result<()> {
|
||||
let mut skip = indent;
|
||||
while self.ml_skip_white()? && skip > 0 {
|
||||
skip -= 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_ml_string<'de, V>(&mut self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.str_buf.clear();
|
||||
|
||||
// Parse a multiline string value.
|
||||
let mut triple = 0;
|
||||
|
||||
// we are at ''' +1 - get indent
|
||||
let (_, col) = self.rdr.pos();
|
||||
let indent = col - 4;
|
||||
|
||||
// skip white/to (newline)
|
||||
while self.ml_skip_white()? {}
|
||||
if self.rdr.peek_or_null()? == b'\n' {
|
||||
self.rdr.eat_char();
|
||||
self.ml_skip_indent(indent)?;
|
||||
}
|
||||
|
||||
// When parsing multiline string values, we must look for ' characters.
|
||||
loop {
|
||||
if self.rdr.eof()? {
|
||||
return Err(self.rdr.error(ErrorCode::EofWhileParsingString));
|
||||
} // todo error("Bad multiline string");
|
||||
let ch = self.rdr.next_char_or_null()?;
|
||||
|
||||
if ch == b'\'' {
|
||||
triple += 1;
|
||||
if triple == 3 {
|
||||
if self.str_buf.last() == Some(&b'\n') {
|
||||
self.str_buf.pop();
|
||||
}
|
||||
let res = str::from_utf8(&self.str_buf).expect("Internal error: json parsing");
|
||||
//todo if (self.str_buf.slice(-1) === '\n') self.str_buf=self.str_buf.slice(0, -1); // remove last EOL
|
||||
return visitor.visit_str(res);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while triple > 0 {
|
||||
self.str_buf.push(b'\'');
|
||||
triple -= 1;
|
||||
}
|
||||
|
||||
if ch != b'\r' {
|
||||
self.str_buf.push(ch);
|
||||
}
|
||||
if ch == b'\n' {
|
||||
self.ml_skip_indent(indent)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_string(&mut self) -> Result<()> {
|
||||
self.str_buf.clear();
|
||||
|
||||
loop {
|
||||
let ch = match self.rdr.next_char()? {
|
||||
Some(ch) => ch,
|
||||
None => {
|
||||
return Err(self.rdr.error(ErrorCode::EofWhileParsingString));
|
||||
}
|
||||
};
|
||||
|
||||
match ch {
|
||||
b'"' => {
|
||||
return Ok(());
|
||||
}
|
||||
b'\\' => {
|
||||
let ch = match self.rdr.next_char()? {
|
||||
Some(ch) => ch,
|
||||
None => {
|
||||
return Err(self.rdr.error(ErrorCode::EofWhileParsingString));
|
||||
}
|
||||
};
|
||||
|
||||
match ch {
|
||||
b'"' => self.str_buf.push(b'"'),
|
||||
b'\\' => self.str_buf.push(b'\\'),
|
||||
b'/' => self.str_buf.push(b'/'),
|
||||
b'b' => self.str_buf.push(b'\x08'),
|
||||
b'f' => self.str_buf.push(b'\x0c'),
|
||||
b'n' => self.str_buf.push(b'\n'),
|
||||
b'r' => self.str_buf.push(b'\r'),
|
||||
b't' => self.str_buf.push(b'\t'),
|
||||
b'u' => {
|
||||
let c = match self.decode_hex_escape()? {
|
||||
0xDC00..=0xDFFF => {
|
||||
return Err(self
|
||||
.rdr
|
||||
.error(ErrorCode::LoneLeadingSurrogateInHexEscape));
|
||||
}
|
||||
|
||||
// Non-BMP characters are encoded as a sequence of
|
||||
// two hex escapes, representing UTF-16 surrogates.
|
||||
n1 @ 0xD800..=0xDBFF => {
|
||||
match (self.rdr.next_char()?, self.rdr.next_char()?) {
|
||||
(Some(b'\\'), Some(b'u')) => (),
|
||||
_ => {
|
||||
return Err(self
|
||||
.rdr
|
||||
.error(ErrorCode::UnexpectedEndOfHexEscape));
|
||||
}
|
||||
}
|
||||
|
||||
let n2 = self.decode_hex_escape()?;
|
||||
|
||||
if !(0xDC00..=0xDFFF).contains(&n2) {
|
||||
return Err(self
|
||||
.rdr
|
||||
.error(ErrorCode::LoneLeadingSurrogateInHexEscape));
|
||||
}
|
||||
|
||||
let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32)
|
||||
+ 0x1_0000;
|
||||
|
||||
match char::from_u32(n as u32) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(self
|
||||
.rdr
|
||||
.error(ErrorCode::InvalidUnicodeCodePoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n => match char::from_u32(n as u32) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(self
|
||||
.rdr
|
||||
.error(ErrorCode::InvalidUnicodeCodePoint));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
self.str_buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes());
|
||||
}
|
||||
_ => {
|
||||
return Err(self.rdr.error(ErrorCode::InvalidEscape));
|
||||
}
|
||||
}
|
||||
}
|
||||
ch => {
|
||||
self.str_buf.push(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_object_colon(&mut self) -> Result<()> {
|
||||
self.rdr.parse_whitespace()?;
|
||||
|
||||
match self.rdr.next_char()? {
|
||||
Some(b':') => Ok(()),
|
||||
Some(_) => Err(self.rdr.error(ErrorCode::ExpectedColon)),
|
||||
None => Err(self.rdr.error(ErrorCode::EofWhileParsingObject)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, Iter> de::Deserializer<'de> for &'a mut Deserializer<Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
if let State::Root = self.state {}
|
||||
|
||||
self.parse_value(visitor)
|
||||
}
|
||||
|
||||
/// Parses a `null` as a None, and any other values as a `Some(...)`.
|
||||
#[inline]
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.rdr.parse_whitespace()?;
|
||||
|
||||
match self.rdr.peek_or_null()? {
|
||||
b'n' => {
|
||||
self.rdr.eat_char();
|
||||
self.parse_ident(b"ull")?;
|
||||
visitor.visit_none()
|
||||
}
|
||||
_ => visitor.visit_some(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a newtype struct as the underlying value.
|
||||
#[inline]
|
||||
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf unit unit_struct seq tuple map
|
||||
tuple_struct struct enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
struct SeqVisitor<'a, Iter: 'a + Iterator<Item = u8>> {
|
||||
de: &'a mut Deserializer<Iter>,
|
||||
}
|
||||
|
||||
impl<'a, Iter: Iterator<Item = u8>> SeqVisitor<'a, Iter> {
|
||||
fn new(de: &'a mut Deserializer<Iter>) -> Self {
|
||||
SeqVisitor { de }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, Iter> de::SeqAccess<'de> for SeqVisitor<'a, Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.de.rdr.parse_whitespace()?;
|
||||
|
||||
match self.de.rdr.peek()? {
|
||||
Some(b']') => {
|
||||
return Ok(None);
|
||||
}
|
||||
Some(_) => {}
|
||||
None => {
|
||||
return Err(self.de.rdr.error(ErrorCode::EofWhileParsingList));
|
||||
}
|
||||
}
|
||||
|
||||
let value = seed.deserialize(&mut *self.de)?;
|
||||
|
||||
// in Hjson the comma is optional and trailing commas are allowed
|
||||
self.de.rdr.parse_whitespace()?;
|
||||
if self.de.rdr.peek()? == Some(b',') {
|
||||
self.de.rdr.eat_char();
|
||||
self.de.rdr.parse_whitespace()?;
|
||||
}
|
||||
|
||||
Ok(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
struct MapVisitor<'a, Iter: 'a + Iterator<Item = u8>> {
|
||||
de: &'a mut Deserializer<Iter>,
|
||||
first: bool,
|
||||
root: bool,
|
||||
}
|
||||
|
||||
impl<'a, Iter: Iterator<Item = u8>> MapVisitor<'a, Iter> {
|
||||
fn new(de: &'a mut Deserializer<Iter>, root: bool) -> Self {
|
||||
MapVisitor {
|
||||
de,
|
||||
first: true,
|
||||
root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, Iter> de::MapAccess<'de> for MapVisitor<'a, Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
|
||||
where
|
||||
K: de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.de.rdr.parse_whitespace()?;
|
||||
|
||||
if self.first {
|
||||
self.first = false;
|
||||
} else if self.de.rdr.peek()? == Some(b',') {
|
||||
// in Hjson the comma is optional and trailing commas are allowed
|
||||
self.de.rdr.eat_char();
|
||||
self.de.rdr.parse_whitespace()?;
|
||||
}
|
||||
|
||||
match self.de.rdr.peek()? {
|
||||
Some(b'}') => return Ok(None), // handled later for root
|
||||
Some(_) => {}
|
||||
None => {
|
||||
if self.root {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(self.de.rdr.error(ErrorCode::EofWhileParsingObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self.de.rdr.peek()? {
|
||||
Some(ch) => {
|
||||
self.de.state = if ch == b'"' {
|
||||
State::Normal
|
||||
} else {
|
||||
State::Keyname
|
||||
};
|
||||
Ok(Some(seed.deserialize(&mut *self.de)?))
|
||||
}
|
||||
None => Err(self.de.rdr.error(ErrorCode::EofWhileParsingValue)),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.de.parse_object_colon()?;
|
||||
|
||||
seed.deserialize(&mut *self.de)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, Iter> de::VariantAccess<'de> for &'a mut Deserializer<Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn unit_variant(self) -> Result<()> {
|
||||
de::Deserialize::deserialize(self)
|
||||
}
|
||||
|
||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self)
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
de::Deserializer::deserialize_any(self, visitor)
|
||||
}
|
||||
|
||||
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
de::Deserializer::deserialize_any(self, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Iterator that deserializes a stream into multiple Hjson values.
|
||||
pub struct StreamDeserializer<T, Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
deser: Deserializer<Iter>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, Iter> StreamDeserializer<T, Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
/// Returns an `Iterator` of decoded Hjson values from an iterator over
|
||||
/// `Iterator<Item=u8>`.
|
||||
pub fn new(iter: Iter) -> StreamDeserializer<T, Iter> {
|
||||
StreamDeserializer {
|
||||
deser: Deserializer::new(iter),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Iter> Iterator for StreamDeserializer<T, Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
type Item = Result<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<T>> {
|
||||
// skip whitespaces, if any
|
||||
// this helps with trailing whitespaces, since whitespaces between
|
||||
// values are handled for us.
|
||||
if let Err(e) = self.deser.rdr.parse_whitespace() {
|
||||
return Some(Err(e));
|
||||
};
|
||||
|
||||
match self.deser.rdr.eof() {
|
||||
Ok(true) => None,
|
||||
Ok(false) => match de::Deserialize::deserialize(&mut self.deser) {
|
||||
Ok(v) => Some(Ok(v)),
|
||||
Err(e) => Some(Err(e)),
|
||||
},
|
||||
Err(e) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Decodes a Hjson value from an iterator over an iterator
|
||||
/// `Iterator<Item=u8>`.
|
||||
pub fn from_iter<I, T>(iter: I) -> Result<T>
|
||||
where
|
||||
I: Iterator<Item = io::Result<u8>>,
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
let fold: io::Result<Vec<_>> = iter.collect();
|
||||
|
||||
if let Err(e) = fold {
|
||||
return Err(Error::Io(e));
|
||||
}
|
||||
|
||||
let bytes = fold.expect("Internal error: json parsing");
|
||||
|
||||
// deserialize tries first to decode with legacy support (new_for_root)
|
||||
// and then with the standard method if this fails.
|
||||
// todo: add compile switch
|
||||
|
||||
// deserialize and make sure the whole stream has been consumed
|
||||
let mut de = Deserializer::new_for_root(bytes.iter().copied());
|
||||
de::Deserialize::deserialize(&mut de)
|
||||
.and_then(|x| de.end().map(|()| x))
|
||||
.or_else(|_| {
|
||||
let mut de2 = Deserializer::new(bytes.iter().copied());
|
||||
de::Deserialize::deserialize(&mut de2).and_then(|x| de2.end().map(|()| x))
|
||||
})
|
||||
|
||||
/* without legacy support:
|
||||
// deserialize and make sure the whole stream has been consumed
|
||||
let mut de = Deserializer::new(bytes.iter().map(|b| *b));
|
||||
let value = match de::Deserialize::deserialize(&mut de)
|
||||
.and_then(|x| { try!(de.end()); Ok(x) })
|
||||
{
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
/// Decodes a Hjson value from a `std::io::Read`.
|
||||
pub fn from_reader<R, T>(rdr: R) -> Result<T>
|
||||
where
|
||||
R: io::Read,
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
from_iter(rdr.bytes())
|
||||
}
|
||||
|
||||
/// Decodes a Hjson value from a byte slice `&[u8]`.
|
||||
pub fn from_slice<T>(v: &[u8]) -> Result<T>
|
||||
where
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
from_iter(v.iter().map(|&byte| Ok(byte)))
|
||||
}
|
||||
|
||||
/// Decodes a Hjson value from a `&str`.
|
||||
pub fn from_str<T>(s: &str) -> Result<T>
|
||||
where
|
||||
T: de::DeserializeOwned,
|
||||
{
|
||||
from_slice(s.as_bytes())
|
||||
}
|
166
crates/nu-json/src/error.rs
Normal file
166
crates/nu-json/src/error.rs
Normal file
@ -0,0 +1,166 @@
|
||||
//! JSON Errors
|
||||
//!
|
||||
//! This module is centered around the `Error` and `ErrorCode` types, which represents all possible
|
||||
//! `serde_hjson` errors.
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::result;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use serde::de;
|
||||
use serde::ser;
|
||||
|
||||
/// The errors that can arise while parsing a JSON stream.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum ErrorCode {
|
||||
/// Catchall for syntax error messages
|
||||
Custom(String),
|
||||
|
||||
/// EOF while parsing a list.
|
||||
EofWhileParsingList,
|
||||
|
||||
/// EOF while parsing an object.
|
||||
EofWhileParsingObject,
|
||||
|
||||
/// EOF while parsing a string.
|
||||
EofWhileParsingString,
|
||||
|
||||
/// EOF while parsing a JSON value.
|
||||
EofWhileParsingValue,
|
||||
|
||||
/// Expected this character to be a `':'`.
|
||||
ExpectedColon,
|
||||
|
||||
/// Expected this character to be either a `','` or a `]`.
|
||||
ExpectedListCommaOrEnd,
|
||||
|
||||
/// Expected this character to be either a `','` or a `}`.
|
||||
ExpectedObjectCommaOrEnd,
|
||||
|
||||
/// Expected to parse either a `true`, `false`, or a `null`.
|
||||
ExpectedSomeIdent,
|
||||
|
||||
/// Expected this character to start a JSON value.
|
||||
ExpectedSomeValue,
|
||||
|
||||
/// Invalid hex escape code.
|
||||
InvalidEscape,
|
||||
|
||||
/// Invalid number.
|
||||
InvalidNumber,
|
||||
|
||||
/// Invalid Unicode code point.
|
||||
InvalidUnicodeCodePoint,
|
||||
|
||||
/// Object key is not a string.
|
||||
KeyMustBeAString,
|
||||
|
||||
/// Lone leading surrogate in hex escape.
|
||||
LoneLeadingSurrogateInHexEscape,
|
||||
|
||||
/// JSON has non-whitespace trailing characters after the value.
|
||||
TrailingCharacters,
|
||||
|
||||
/// Unexpected end of hex escape.
|
||||
UnexpectedEndOfHexEscape,
|
||||
|
||||
/// Found a punctuator character when expecting a quoteless string.
|
||||
PunctuatorInQlString,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ErrorCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//use std::fmt::Debug;
|
||||
|
||||
match *self {
|
||||
ErrorCode::Custom(ref msg) => write!(f, "{}", msg),
|
||||
ErrorCode::EofWhileParsingList => "EOF while parsing a list".fmt(f),
|
||||
ErrorCode::EofWhileParsingObject => "EOF while parsing an object".fmt(f),
|
||||
ErrorCode::EofWhileParsingString => "EOF while parsing a string".fmt(f),
|
||||
ErrorCode::EofWhileParsingValue => "EOF while parsing a value".fmt(f),
|
||||
ErrorCode::ExpectedColon => "expected `:`".fmt(f),
|
||||
ErrorCode::ExpectedListCommaOrEnd => "expected `,` or `]`".fmt(f),
|
||||
ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f),
|
||||
ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f),
|
||||
ErrorCode::ExpectedSomeValue => "expected value".fmt(f),
|
||||
ErrorCode::InvalidEscape => "invalid escape".fmt(f),
|
||||
ErrorCode::InvalidNumber => "invalid number".fmt(f),
|
||||
ErrorCode::InvalidUnicodeCodePoint => "invalid Unicode code point".fmt(f),
|
||||
ErrorCode::KeyMustBeAString => "key must be a string".fmt(f),
|
||||
ErrorCode::LoneLeadingSurrogateInHexEscape => {
|
||||
"lone leading surrogate in hex escape".fmt(f)
|
||||
}
|
||||
ErrorCode::TrailingCharacters => "trailing characters".fmt(f),
|
||||
ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f),
|
||||
ErrorCode::PunctuatorInQlString => {
|
||||
"found a punctuator character when expecting a quoteless string".fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This type represents all possible errors that can occur when serializing or deserializing a
|
||||
/// value into JSON.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The JSON value had some syntactic error.
|
||||
Syntax(ErrorCode, usize, usize),
|
||||
|
||||
/// Some IO error occurred when serializing or deserializing a value.
|
||||
Io(io::Error),
|
||||
|
||||
/// Some UTF8 error occurred while serializing or deserializing a value.
|
||||
FromUtf8(FromUtf8Error),
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn cause(&self) -> Option<&dyn error::Error> {
|
||||
match *self {
|
||||
Error::Io(ref error) => Some(error),
|
||||
Error::FromUtf8(ref error) => Some(error),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::Syntax(ref code, line, col) => {
|
||||
write!(fmt, "{:?} at line {} column {}", code, line, col)
|
||||
}
|
||||
Error::Io(ref error) => fmt::Display::fmt(error, fmt),
|
||||
Error::FromUtf8(ref error) => fmt::Display::fmt(error, fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(error: io::Error) -> Error {
|
||||
Error::Io(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromUtf8Error> for Error {
|
||||
fn from(error: FromUtf8Error) -> Error {
|
||||
Error::FromUtf8(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Error {
|
||||
Error::Syntax(ErrorCode::Custom(msg.to_string()), 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
fn custom<T: fmt::Display>(msg: T) -> Error {
|
||||
Error::Syntax(ErrorCode::Custom(msg.to_string()), 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper alias for `Result` objects that return a JSON `Error`.
|
||||
pub type Result<T> = result::Result<T, Error>;
|
@ -2,11 +2,7 @@ pub use self::de::{
|
||||
from_iter, from_reader, from_slice, from_str, Deserializer, StreamDeserializer,
|
||||
};
|
||||
pub use self::error::{Error, ErrorCode, Result};
|
||||
<<<<<<< HEAD
|
||||
pub use self::ser::{to_string, to_vec, to_writer, Serializer};
|
||||
=======
|
||||
pub use self::ser::{to_string, to_string_raw, to_vec, to_writer, Serializer};
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
pub use self::value::{from_value, to_value, Map, Value};
|
||||
|
||||
pub mod builder;
|
||||
|
@ -4,20 +4,13 @@
|
||||
|
||||
use std::fmt::{Display, LowerExp};
|
||||
use std::io;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
use std::io::{BufRead, BufReader};
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
use std::num::FpCategory;
|
||||
|
||||
use super::error::{Error, ErrorCode, Result};
|
||||
use serde::ser;
|
||||
|
||||
<<<<<<< HEAD
|
||||
use super::util::ParseNumber;
|
||||
=======
|
||||
//use super::util::ParseNumber;
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
@ -738,13 +731,6 @@ impl<'a> Formatter for HjsonFormatter<'a> {
|
||||
writer.write_all(&[ch]).map_err(From::from)
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
fn comma<W>(&mut self, writer: &mut W, _: bool) -> Result<()>
|
||||
where
|
||||
W: io::Write,
|
||||
{
|
||||
writer.write_all(b"\n")?;
|
||||
=======
|
||||
fn comma<W>(&mut self, writer: &mut W, first: bool) -> Result<()>
|
||||
where
|
||||
W: io::Write,
|
||||
@ -754,7 +740,6 @@ impl<'a> Formatter for HjsonFormatter<'a> {
|
||||
} else {
|
||||
writer.write_all(b"\n")?;
|
||||
}
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
indent(writer, self.current_indent, self.indent)
|
||||
}
|
||||
|
||||
@ -868,18 +853,11 @@ where
|
||||
// Check if we can insert this string without quotes
|
||||
// see hjson syntax (must not parse as true, false, null or number)
|
||||
|
||||
<<<<<<< HEAD
|
||||
let mut pn = ParseNumber::new(value.bytes());
|
||||
let is_number = pn.parse(true).is_ok();
|
||||
|
||||
if is_number || NEEDS_QUOTES.is_match(value) || STARTS_WITH_KEYWORD.is_match(value) {
|
||||
=======
|
||||
//let mut pn = ParseNumber::new(value.bytes());
|
||||
//let is_number = pn.parse(true).is_ok();
|
||||
|
||||
if true {
|
||||
// is_number || NEEDS_QUOTES.is_match(value) || STARTS_WITH_KEYWORD.is_match(value) {
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
// First check if the string can be expressed in multiline format or
|
||||
// we must replace the offending characters with safe escape sequences.
|
||||
|
||||
@ -941,19 +919,11 @@ where
|
||||
}
|
||||
|
||||
// Check if we can insert this name without quotes
|
||||
<<<<<<< HEAD
|
||||
if NEEDS_ESCAPE_NAME.is_match(value) {
|
||||
escape_bytes(wr, value.as_bytes()).map_err(From::from)
|
||||
} else {
|
||||
wr.write_all(value.as_bytes()).map_err(From::from)
|
||||
}
|
||||
=======
|
||||
//if NEEDS_ESCAPE_NAME.is_match(value) {
|
||||
escape_bytes(wr, value.as_bytes()).map_err(From::from)
|
||||
// } else {
|
||||
// wr.write_all(value.as_bytes()).map_err(From::from)
|
||||
// }
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -961,16 +931,11 @@ fn escape_char<W>(wr: &mut W, value: char) -> Result<()>
|
||||
where
|
||||
W: io::Write,
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
let mut scratch = [0_u8; 4];
|
||||
escape_bytes(wr, value.encode_utf8(&mut scratch).as_bytes())
|
||||
=======
|
||||
// FIXME: this allocation is required in order to be compatible with stable
|
||||
// rust, which doesn't support encoding a `char` into a stack buffer.
|
||||
let mut s = String::new();
|
||||
s.push(value);
|
||||
escape_bytes(wr, s.as_bytes())
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
}
|
||||
|
||||
fn fmt_f32_or_null<W>(wr: &mut W, value: f32) -> Result<()>
|
||||
@ -1059,8 +1024,6 @@ where
|
||||
let string = String::from_utf8(vec)?;
|
||||
Ok(string)
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
/// Encode the specified struct into a Hjson `String` buffer.
|
||||
/// And remove all whitespace
|
||||
@ -1087,4 +1050,3 @@ fn remove_json_whitespace(v: Vec<u8>) -> String {
|
||||
}
|
||||
output
|
||||
}
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
|
333
crates/nu-json/src/util.rs
Normal file
333
crates/nu-json/src/util.rs
Normal file
@ -0,0 +1,333 @@
|
||||
use std::io;
|
||||
use std::str;
|
||||
|
||||
use super::error::{Error, ErrorCode, Result};
|
||||
|
||||
pub struct StringReader<Iter: Iterator<Item = u8>> {
|
||||
iter: Iter,
|
||||
line: usize,
|
||||
col: usize,
|
||||
ch: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<Iter> StringReader<Iter>
|
||||
where
|
||||
Iter: Iterator<Item = u8>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(iter: Iter) -> Self {
|
||||
StringReader {
|
||||
iter,
|
||||
line: 1,
|
||||
col: 0,
|
||||
ch: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<u8>> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(b'\n') => {
|
||||
self.line += 1;
|
||||
self.col = 0;
|
||||
Some(Ok(b'\n'))
|
||||
}
|
||||
Some(c) => {
|
||||
self.col += 1;
|
||||
Some(Ok(c))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pos(&mut self) -> (usize, usize) {
|
||||
(self.line, self.col)
|
||||
}
|
||||
|
||||
pub fn eof(&mut self) -> Result<bool> {
|
||||
Ok(self.peek()?.is_none())
|
||||
}
|
||||
|
||||
pub fn peek_next(&mut self, idx: usize) -> Result<Option<u8>> {
|
||||
while self.ch.len() <= idx {
|
||||
match self.next() {
|
||||
Some(Err(err)) => return Err(Error::Io(err)),
|
||||
Some(Ok(ch)) => self.ch.push(ch),
|
||||
None => return Ok(None),
|
||||
}
|
||||
}
|
||||
Ok(Some(self.ch[idx]))
|
||||
}
|
||||
|
||||
// pub fn peek_next_or_null(&mut self, idx: usize) -> Result<u8> {
|
||||
// Ok(try!(self.peek_next(idx)).unwrap_or(b'\x00'))
|
||||
// }
|
||||
|
||||
pub fn peek(&mut self) -> Result<Option<u8>> {
|
||||
self.peek_next(0)
|
||||
}
|
||||
|
||||
pub fn peek_or_null(&mut self) -> Result<u8> {
|
||||
Ok(self.peek()?.unwrap_or(b'\x00'))
|
||||
}
|
||||
|
||||
pub fn eat_char(&mut self) -> u8 {
|
||||
self.ch.remove(0)
|
||||
}
|
||||
|
||||
pub fn uneat_char(&mut self, ch: u8) {
|
||||
self.ch.insert(0, ch);
|
||||
}
|
||||
|
||||
pub fn next_char(&mut self) -> Result<Option<u8>> {
|
||||
match self.ch.first() {
|
||||
Some(&ch) => {
|
||||
self.eat_char();
|
||||
Ok(Some(ch))
|
||||
}
|
||||
None => match self.next() {
|
||||
Some(Err(err)) => Err(Error::Io(err)),
|
||||
Some(Ok(ch)) => Ok(Some(ch)),
|
||||
None => Ok(None),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_char_or_null(&mut self) -> Result<u8> {
|
||||
Ok(self.next_char()?.unwrap_or(b'\x00'))
|
||||
}
|
||||
|
||||
fn eat_line(&mut self) -> Result<()> {
|
||||
loop {
|
||||
match self.peek()? {
|
||||
Some(b'\n') | None => return Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
self.eat_char();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_whitespace(&mut self) -> Result<()> {
|
||||
loop {
|
||||
match self.peek_or_null()? {
|
||||
b' ' | b'\n' | b'\t' | b'\r' => {
|
||||
self.eat_char();
|
||||
}
|
||||
b'#' => self.eat_line()?,
|
||||
b'/' => {
|
||||
match self.peek_next(1)? {
|
||||
Some(b'/') => self.eat_line()?,
|
||||
Some(b'*') => {
|
||||
self.eat_char();
|
||||
self.eat_char();
|
||||
while !(self.peek()?.unwrap_or(b'*') == b'*'
|
||||
&& self.peek_next(1)?.unwrap_or(b'/') == b'/')
|
||||
{
|
||||
self.eat_char();
|
||||
}
|
||||
self.eat_char();
|
||||
self.eat_char();
|
||||
}
|
||||
Some(_) => {
|
||||
self.eat_char();
|
||||
}
|
||||
None => return Err(self.error(ErrorCode::TrailingCharacters)), //todo
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(&mut self, reason: ErrorCode) -> Error {
|
||||
Error::Syntax(reason, self.line, self.col)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Number {
|
||||
I64(i64),
|
||||
U64(u64),
|
||||
F64(f64),
|
||||
}
|
||||
|
||||
pub struct ParseNumber<Iter: Iterator<Item = u8>> {
|
||||
rdr: StringReader<Iter>,
|
||||
result: Vec<u8>,
|
||||
}
|
||||
|
||||
// macro_rules! try_or_invalid {
|
||||
// ($e:expr) => {
|
||||
// match $e {
|
||||
// Some(v) => v,
|
||||
// None => { return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<Iter: Iterator<Item = u8>> ParseNumber<Iter> {
|
||||
#[inline]
|
||||
pub fn new(iter: Iter) -> Self {
|
||||
ParseNumber {
|
||||
rdr: StringReader::new(iter),
|
||||
result: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self, stop_at_next: bool) -> Result<Number> {
|
||||
match self.try_parse() {
|
||||
Ok(()) => {
|
||||
self.rdr.parse_whitespace()?;
|
||||
|
||||
let mut ch = self.rdr.next_char_or_null()?;
|
||||
|
||||
if stop_at_next {
|
||||
let ch2 = self.rdr.peek_or_null()?;
|
||||
// end scan if we find a punctuator character like ,}] or a comment
|
||||
if ch == b','
|
||||
|| ch == b'}'
|
||||
|| ch == b']'
|
||||
|| ch == b'#'
|
||||
|| ch == b'/' && (ch2 == b'/' || ch2 == b'*')
|
||||
{
|
||||
ch = b'\x00';
|
||||
}
|
||||
}
|
||||
|
||||
match ch {
|
||||
b'\x00' => {
|
||||
let res =
|
||||
str::from_utf8(&self.result).expect("Internal error: json parsing");
|
||||
|
||||
let mut is_float = false;
|
||||
for ch in res.chars() {
|
||||
if ch == '.' || ch == 'e' || ch == 'E' {
|
||||
is_float = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if is_float {
|
||||
Ok(Number::F64(
|
||||
res.parse::<f64>().expect("Internal error: json parsing"),
|
||||
))
|
||||
} else if res.starts_with('-') {
|
||||
Ok(Number::I64(
|
||||
res.parse::<i64>().expect("Internal error: json parsing"),
|
||||
))
|
||||
} else {
|
||||
Ok(Number::U64(
|
||||
res.parse::<u64>().expect("Internal error: json parsing"),
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)),
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_parse(&mut self) -> Result<()> {
|
||||
if self.rdr.peek_or_null()? == b'-' {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
}
|
||||
|
||||
let mut has_value = false;
|
||||
|
||||
if self.rdr.peek_or_null()? == b'0' {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
has_value = true;
|
||||
|
||||
// There can be only one leading '0'.
|
||||
if let b'0'..=b'9' = self.rdr.peek_or_null()? {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match self.rdr.peek_or_null()? {
|
||||
b'0'..=b'9' => {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
has_value = true;
|
||||
}
|
||||
b'.' => {
|
||||
if !has_value {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
self.rdr.eat_char();
|
||||
return self.try_decimal();
|
||||
}
|
||||
b'e' | b'E' => {
|
||||
if !has_value {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
self.rdr.eat_char();
|
||||
return self.try_exponent();
|
||||
}
|
||||
_ => {
|
||||
if !has_value {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_decimal(&mut self) -> Result<()> {
|
||||
self.result.push(b'.');
|
||||
|
||||
// Make sure a digit follows the decimal place.
|
||||
match self.rdr.next_char_or_null()? {
|
||||
c @ b'0'..=b'9' => {
|
||||
self.result.push(c);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
};
|
||||
|
||||
while let b'0'..=b'9' = self.rdr.peek_or_null()? {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
}
|
||||
|
||||
match self.rdr.peek_or_null()? {
|
||||
b'e' | b'E' => {
|
||||
self.rdr.eat_char();
|
||||
self.try_exponent()
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_exponent(&mut self) -> Result<()> {
|
||||
self.result.push(b'e');
|
||||
|
||||
match self.rdr.peek_or_null()? {
|
||||
b'+' => {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
}
|
||||
b'-' => {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// Make sure a digit follows the exponent place.
|
||||
match self.rdr.next_char_or_null()? {
|
||||
c @ b'0'..=b'9' => {
|
||||
self.result.push(c);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0));
|
||||
}
|
||||
};
|
||||
|
||||
while let b'0'..=b'9' = self.rdr.peek_or_null()? {
|
||||
self.result.push(self.rdr.eat_char());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
1158
crates/nu-json/src/value.rs
Normal file
1158
crates/nu-json/src/value.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,5 @@
|
||||
<<<<<<< HEAD
|
||||
extern crate nu_json;
|
||||
extern crate nu_test_support;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
=======
|
||||
// FIXME: re-enable tests
|
||||
/*
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
use nu_json::Value;
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
@ -216,8 +208,5 @@ fn test_hjson() {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
*/
|
||||
>>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce
|
||||
|
Reference in New Issue
Block a user