#![deny(missing_docs)]
use std::{
collections::{HashMap, HashSet},
fmt::{Debug, Display, Write},
};
use environment::Environment;
use identifier::Identifier;
use interpreter::{eval, Expression};
use lexer::{tokenize, tokenize_and_filter, transform, Token};
use parser::{parse, Element};
use serde::{Deserialize, Serialize};
use translation::translate;
#[doc(hidden)]
pub mod environment;
#[doc(hidden)]
pub mod interpreter;
#[doc(hidden)]
pub mod lexer;
#[doc(hidden)]
pub mod parser;
#[doc(hidden)]
pub mod preludes;
#[doc(hidden)]
pub mod translation;
pub mod identifier;
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
pub struct WanderError(pub String);
pub trait HostType: Debug + PartialEq + Eq + Serialize + Clone + Display + Serialize {}
impl<T> HostType for T where T: Debug + PartialEq + Eq + Serialize + Clone + Display + Serialize {}
pub trait TypeChecker<T: HostType> {
fn check(&self, value: WanderValue<T>, tag: WanderValue<T>) -> Result<bool, WanderError>;
}
pub struct EpsilonChecker {}
impl<T: HostType> TypeChecker<T> for EpsilonChecker {
fn check(&self, _value: WanderValue<T>, _tag: WanderValue<T>) -> Result<bool, WanderError> {
Ok(true)
}
}
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
pub struct NoHostType {}
impl Display for NoHostType {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
panic!("NoHostType should never be displayed.")
}
}
pub struct HostFunctionBinding {
pub name: String,
pub parameters: Vec<(String, Option<String>)>,
pub result: Option<String>,
pub doc_string: String,
}
pub trait HostFunction<T: HostType> {
fn run(
&self,
arguments: &[WanderValue<T>],
bindings: &Environment<T>,
) -> Result<WanderValue<T>, WanderError>;
fn binding(&self) -> HostFunctionBinding;
}
pub type TokenTransformer = fn(&[Token]) -> Result<Vec<Token>, WanderError>;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct HostValue<T> {
pub value: T,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum WanderValue<T: Clone + PartialEq + Eq> {
Bool(bool),
Int(i64),
String(String),
Identifier(Identifier),
Nothing,
Lambda(String, Option<String>, Option<String>, Box<Element>),
List(Vec<WanderValue<T>>),
Tuple(Vec<WanderValue<T>>),
Set(HashSet<WanderValue<T>>),
Record(HashMap<String, WanderValue<T>>),
HostValue(HostValue<T>),
}
impl<T: Clone + PartialEq + Eq> core::hash::Hash for WanderValue<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct PartialApplication<T: Clone + PartialEq + Eq> {
arguments: Vec<WanderValue<T>>,
callee: WanderValue<T>,
}
pub fn write_integer(integer: &i64) -> String {
format!("{}", integer)
}
pub fn write_float(float: &f64) -> String {
let res = format!("{}", float);
if res.contains('.') {
res
} else {
res + ".0"
}
}
pub fn write_string(string: &str) -> String {
let escaped_string = string
.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t");
format!("\"{}\"", escaped_string)
}
fn write_list_or_tuple_wander_value<T: Clone + Display + PartialEq + Eq + Debug>(
open: &str,
close: char,
contents: &Vec<WanderValue<T>>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.write_str(open).unwrap();
let mut i = 0;
for value in contents {
write!(f, "{value}").unwrap();
i += 1;
if i < contents.len() {
write!(f, " ").unwrap();
}
}
write!(f, "{close}")
}
fn write_set<T: Clone + Display + PartialEq + Eq + Debug>(
contents: &HashSet<WanderValue<T>>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.write_str("#(").unwrap();
let mut i = 0;
for value in contents {
write!(f, "{value}").unwrap();
i += 1;
if i < contents.len() {
write!(f, " ").unwrap();
}
}
f.write_char(')')
}
fn write_host_value<T: Display + PartialEq + Eq>(
value: &HostValue<T>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{}", value.value)
}
fn write_record<T: Clone + Display + PartialEq + Eq + Debug>(
contents: &HashMap<String, WanderValue<T>>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{{").unwrap();
let mut i = 0;
for (name, value) in contents {
write!(f, "{name} = {value}").unwrap();
i += 1;
if i < contents.len() {
write!(f, " ").unwrap();
}
}
write!(f, "}}")
}
impl<T: Clone + Display + PartialEq + Eq + std::fmt::Debug> Display for WanderValue<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WanderValue::Bool(value) => write!(f, "{}", value),
WanderValue::Int(value) => write!(f, "{}", value),
WanderValue::String(value) => f.write_str(&write_string(value)),
WanderValue::Identifier(value) => write!(f, "<{}>", value.id()),
WanderValue::Nothing => write!(f, "nothing"),
WanderValue::List(contents) => write_list_or_tuple_wander_value("[", ']', contents, f),
WanderValue::HostValue(value) => write_host_value(value, f),
WanderValue::Tuple(contents) => {
write_list_or_tuple_wander_value("'(", ')', contents, f)
}
WanderValue::Record(values) => write_record(values, f),
WanderValue::Lambda(p, i, o, b) => write!(
f,
"[lambda {:?}]",
WanderValue::Lambda::<T>(p.clone(), i.clone(), o.clone(), b.clone())
),
WanderValue::Set(contents) => write_set(contents, f),
}
}
}
pub fn run<T: HostType + Display>(
script: &str,
bindings: &mut Environment<T>,
) -> Result<WanderValue<T>, WanderError> {
let tokens = tokenize_and_filter(script)?;
let tokens = transform(&tokens, bindings)?;
let elements = parse(tokens)?;
let expression = translate(elements)?;
eval(&expression, bindings)
}
#[derive(Debug, Serialize)]
pub struct Introspection {
pub tokens_ws: Vec<Token>,
pub tokens: Vec<Token>,
pub tokens_transformed: Vec<Token>,
pub element: Element,
pub expression: Expression,
}
pub fn introspect<T: HostType>(
script: &str,
bindings: &Environment<T>,
) -> Result<Introspection, WanderError> {
let tokens_ws = tokenize(script).or(Ok(vec![]))?;
let tokens = tokenize_and_filter(script).or(Ok(vec![]))?;
let tokens_transformed = transform(&tokens.clone(), bindings).or(Ok(vec![]))?;
let element = parse(tokens_transformed.clone()).or(Ok(Element::String("Error".to_owned())))?; let expression = translate(element.clone()).or(Ok(Expression::String("Error".to_owned())))?; Ok(Introspection {
tokens_ws,
tokens,
tokens_transformed,
element,
expression,
})
}