#![deny(missing_docs)]
use std::{
collections::HashMap,
fmt::{Display, Write},
};
use bindings::Bindings;
use interpreter::eval;
use lexer::{tokenize, transform, Token};
use parser::{parse, Element};
use serde::{Deserialize, Serialize};
use translation::translate;
#[doc(hidden)]
pub mod bindings;
#[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;
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct WanderError(pub String);
#[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<WanderType>,
pub result: WanderType,
pub doc_string: String,
}
pub trait HostFunction<T: Clone + PartialEq> {
fn run(
&self,
arguments: &[WanderValue<T>],
bindings: &Bindings<T>,
) -> Result<WanderValue<T>, WanderError>;
fn binding(&self) -> HostFunctionBinding;
}
pub type TokenTransformer = fn(&[Token]) -> Result<Vec<Token>, WanderError>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WanderType {
Any,
Boolean,
Int,
String,
Nothing,
HostFunction,
Lambda,
List,
Tuple,
Optional(Box<WanderType>),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct HostValue<T> {
pub value: T,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum WanderValue<T: Clone> {
Boolean(bool),
Int(i64),
String(String),
Nothing,
HostedFunction(String),
Lambda(Vec<String>, Vec<Element>),
PartialApplication(Box<PartialApplication<T>>),
List(Vec<WanderValue<T>>),
Tuple(Vec<WanderValue<T>>),
Record(HashMap<String, WanderValue<T>>),
HostValue(HostValue<T>),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct PartialApplication<T: Clone> {
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>(
open: char,
close: char,
contents: &Vec<WanderValue<T>>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.write_char(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_host_value<T: Display + PartialEq>(
value: &HostValue<T>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{}", value.value)
}
fn write_record<T: Clone + Display + PartialEq>(
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> Display for WanderValue<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WanderValue::Boolean(value) => write!(f, "{}", value),
WanderValue::Int(value) => write!(f, "{}", value),
WanderValue::String(value) => f.write_str(&write_string(value)),
WanderValue::Nothing => write!(f, "nothing"),
WanderValue::HostedFunction(_) => write!(f, "[function]"),
WanderValue::List(contents) => write_list_or_tuple_wander_value('[', ']', contents, f),
WanderValue::Lambda(_, _) => write!(f, "[lambda]"),
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::PartialApplication(_) => write!(f, "[application]"),
}
}
}
pub fn run<T: Clone + Display + PartialEq>(
script: &str,
bindings: &mut Bindings<T>,
) -> Result<WanderValue<T>, WanderError> {
let tokens = tokenize(script)?;
let tokens = transform(&tokens, bindings)?;
let elements = parse(tokens)?;
let elements = translate(elements)?;
eval(&elements, bindings)
}