mirror of
https://github.com/tweag/nickel.git
synced 2024-11-10 10:46:49 +03:00
Implement hash and (de)serialize operators
This commit is contained in:
parent
eaffccde11
commit
89fdb39ed3
26
src/error.rs
26
src/error.rs
@ -70,6 +70,14 @@ pub enum EvalError {
|
||||
UnboundIdentifier(Ident, Option<RawSpan>),
|
||||
/// A thunk was entered during its own update.
|
||||
InfiniteRecursion(CallStack, Option<RawSpan>),
|
||||
/// A serialization error occurred during a call to the builtin `serialize`.
|
||||
SerializationError(SerializationError),
|
||||
/// A parse error occurred during a call to the builtin `deserialize`.
|
||||
DeserializationError(
|
||||
String, /* format */
|
||||
String, /* error message */
|
||||
Option<RawSpan>, /* position of the call to deserialize */
|
||||
),
|
||||
/// An unexpected internal error.
|
||||
InternalError(String, Option<RawSpan>),
|
||||
/// Errors occurring rarely enough to not deserve a dedicated variant.
|
||||
@ -285,6 +293,12 @@ impl From<std::io::Error> for IOError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SerializationError> for EvalError {
|
||||
fn from(error: SerializationError) -> EvalError {
|
||||
EvalError::SerializationError(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an escaped version of a string. Used to sanitize strings before inclusion in error
|
||||
/// messages, which can contain ASCII code sequences, and in particular ANSI escape codes, that
|
||||
/// could alter Nickel's error messages.
|
||||
@ -1007,6 +1021,18 @@ impl ToDiagnostic<FileId> for EvalError {
|
||||
.with_labels(labels)
|
||||
.with_notes(vec![String::from(INTERNAL_ERROR_MSG)])]
|
||||
}
|
||||
EvalError::SerializationError(err) => err.to_diagnostic(files, contract_id),
|
||||
EvalError::DeserializationError(format, msg, span_opt) => {
|
||||
let labels = span_opt
|
||||
.as_ref()
|
||||
.map(|span| vec![primary(span).with_message("here")])
|
||||
.unwrap_or(Vec::new());
|
||||
|
||||
vec![Diagnostic::error()
|
||||
.with_message(format!("{} parse error: {}", format, msg))
|
||||
.with_labels(labels)
|
||||
.with_notes(vec![String::from(INTERNAL_ERROR_MSG)])]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
164
src/operation.rs
164
src/operation.rs
@ -6,19 +6,20 @@
|
||||
//! the functions [`process_unary_operation`](fn.process_unary_operation.html) and
|
||||
//! [`process_binary_operation`](fn.process_binary_operation.html) receive evaluated operands and
|
||||
//! implement the actual semantics of operators.
|
||||
use crate::error::EvalError;
|
||||
use crate::eval::Environment;
|
||||
use crate::eval::{CallStack, Closure};
|
||||
use crate::error::{EvalError, SerializationError};
|
||||
use crate::eval::{subst, CallStack, Closure, Environment};
|
||||
use crate::identifier::Ident;
|
||||
use crate::label::ty_path;
|
||||
use crate::merge;
|
||||
use crate::merge::merge;
|
||||
use crate::position::RawSpan;
|
||||
use crate::serialize;
|
||||
use crate::stack::Stack;
|
||||
use crate::term::make as mk_term;
|
||||
use crate::term::{BinaryOp, RichTerm, StrChunk, Term, UnaryOp};
|
||||
use crate::transformations::Closurizable;
|
||||
use crate::{mk_app, mk_fun};
|
||||
use md5::digest::Digest;
|
||||
use simple_counter::*;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::Extend;
|
||||
@ -1315,6 +1316,163 @@ fn process_binary_operation(
|
||||
env2,
|
||||
pos_op,
|
||||
),
|
||||
BinaryOp::Hash() => {
|
||||
let mk_err_fst = |t1| {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Enum <Md5, Sha1, Sha256, Sha512>"),
|
||||
String::from("hash, 1st argument"),
|
||||
fst_pos,
|
||||
RichTerm {
|
||||
term: t1,
|
||||
pos: pos1,
|
||||
},
|
||||
))
|
||||
};
|
||||
|
||||
if let Term::Enum(ref id) = t1.as_ref() {
|
||||
if let Term::Str(s) = *t2 {
|
||||
let result = match id.to_string().as_str() {
|
||||
"Md5" => {
|
||||
let mut hasher = md5::Md5::new();
|
||||
hasher.update(s);
|
||||
format!("{:x}", hasher.finalize())
|
||||
}
|
||||
"Sha1" => {
|
||||
let mut hasher = sha1::Sha1::new();
|
||||
hasher.update(s);
|
||||
format!("{:x}", hasher.finalize())
|
||||
}
|
||||
"Sha256" => {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(s);
|
||||
format!("{:x}", hasher.finalize())
|
||||
}
|
||||
"Sha512" => {
|
||||
let mut hasher = sha2::Sha512::new();
|
||||
hasher.update(s);
|
||||
format!("{:x}", hasher.finalize())
|
||||
}
|
||||
_ => return mk_err_fst(t1),
|
||||
};
|
||||
|
||||
Ok(Closure::atomic_closure(
|
||||
Term::Str(String::from(result)).into(),
|
||||
))
|
||||
} else {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Str"),
|
||||
String::from("hash, 2nd argument"),
|
||||
snd_pos,
|
||||
RichTerm {
|
||||
term: t2,
|
||||
pos: pos2,
|
||||
},
|
||||
))
|
||||
}
|
||||
} else {
|
||||
mk_err_fst(t1)
|
||||
}
|
||||
}
|
||||
BinaryOp::Serialize() => {
|
||||
let mk_err_fst = |t1| {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Enum <Json, Yaml, Toml>"),
|
||||
String::from("serialize, 1st argument"),
|
||||
fst_pos,
|
||||
RichTerm {
|
||||
term: t1,
|
||||
pos: pos1,
|
||||
},
|
||||
))
|
||||
};
|
||||
|
||||
if let Term::Enum(ref id) = t1.as_ref() {
|
||||
// Serialization needs all variables term to be fully substituted
|
||||
let global_env = Environment::new();
|
||||
let rt2 = subst(
|
||||
RichTerm {
|
||||
term: t2,
|
||||
pos: pos2,
|
||||
},
|
||||
&global_env,
|
||||
&env2,
|
||||
)
|
||||
.into();
|
||||
serialize::validate(&rt2)?;
|
||||
|
||||
let result = match id.to_string().as_str() {
|
||||
"Json" => serde_json::to_string_pretty(&rt2)
|
||||
.map_err(|err| SerializationError::Other(err.to_string()))?,
|
||||
"Yaml" => serde_yaml::to_string(&rt2)
|
||||
.map_err(|err| SerializationError::Other(err.to_string()))?,
|
||||
"Toml" => toml::ser::to_string_pretty(&rt2)
|
||||
.map_err(|err| SerializationError::Other(err.to_string()))?,
|
||||
_ => return mk_err_fst(t1),
|
||||
};
|
||||
|
||||
Ok(Closure::atomic_closure(
|
||||
Term::Str(String::from(result)).into(),
|
||||
))
|
||||
} else {
|
||||
mk_err_fst(t1)
|
||||
}
|
||||
}
|
||||
BinaryOp::Deserialize() => {
|
||||
let mk_err_fst = |t1| {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Enum <Json, Yaml, Toml>"),
|
||||
String::from("deserialize, 1st argument"),
|
||||
fst_pos,
|
||||
RichTerm {
|
||||
term: t1,
|
||||
pos: pos1,
|
||||
},
|
||||
))
|
||||
};
|
||||
|
||||
if let Term::Enum(ref id) = t1.as_ref() {
|
||||
if let Term::Str(s) = *t2 {
|
||||
let rt: RichTerm = match id.to_string().as_str() {
|
||||
"Json" => serde_json::from_str(&s).map_err(|err| {
|
||||
EvalError::DeserializationError(
|
||||
String::from("json"),
|
||||
format!("{}", err),
|
||||
pos_op,
|
||||
)
|
||||
})?,
|
||||
"Yaml" => serde_yaml::from_str(&s).map_err(|err| {
|
||||
EvalError::DeserializationError(
|
||||
String::from("yaml"),
|
||||
format!("{}", err),
|
||||
pos_op,
|
||||
)
|
||||
})?,
|
||||
"Toml" => toml::from_str(&s).map_err(|err| {
|
||||
EvalError::DeserializationError(
|
||||
String::from("toml"),
|
||||
format!("{}", err),
|
||||
pos_op,
|
||||
)
|
||||
})?,
|
||||
_ => return mk_err_fst(t1),
|
||||
};
|
||||
|
||||
Ok(Closure::atomic_closure(rt))
|
||||
} else {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Str"),
|
||||
String::from("deserialize, 2nd argument"),
|
||||
snd_pos,
|
||||
RichTerm {
|
||||
term: t2,
|
||||
pos: pos2,
|
||||
},
|
||||
))
|
||||
}
|
||||
} else {
|
||||
mk_err_fst(t1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user