litto 0.1.0

Building blocks for DSL scripting language interpreters that interact with native Rust code.
Documentation
//! Types used by `minilang`.

pub use super::tinylang::types::{NativeProcedure, Nil, Procedure};
use super::tinylang::TinyLang;
use crate::value::AbstractValue;
use crate::Interpreter;
use gcmodule::Trace;
use std::fmt;

type Expr = <super::MiniLang as Interpreter>::Expr;
type Value = <super::MiniLang as Interpreter>::Value;

/// Boolean type.
#[derive(Trace, Debug)]
pub struct Bool(pub bool);

/// Integer type.
#[derive(Trace, Debug)]
pub struct Int(pub i64);

/// String type.
#[derive(Trace, Debug)]
pub struct Str(pub String);

/// List type.
#[derive(Trace, Debug)]
pub struct List(pub Vec<Value>);

/// Quote type (expression).
#[derive(Trace, Debug)]
pub struct Quote(pub Expr);

impl Str {
    /// Converts an escaped string (ex. `"a\nb"`) to a string value.
    pub fn from_escaped(mut string: &str) -> Str {
        // Strip '"' at both ends.
        if string.starts_with('"') && string.ends_with('"') && string.len() >= 2 {
            string = unsafe { string.get_unchecked(1..string.len() - 1) };
        }
        let string = if string.find('\\').is_some() {
            let mut new_string = String::with_capacity(string.len());
            let mut escaped = false;
            for ch in string.chars() {
                match (ch, escaped) {
                    ('\\', false) => {
                        escaped = true;
                    }
                    ('t', true) => {
                        new_string.push('\t');
                    }
                    ('n', true) => {
                        new_string.push('\n');
                    }
                    _ => {
                        new_string.push(ch);
                        escaped = false;
                    }
                }
            }
            new_string
        } else {
            string.to_string()
        };
        Str(string)
    }
}

impl fmt::Display for Bool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = if self.0 { "#t" } else { "#f" };
        write!(f, "{}", s)
    }
}

impl AbstractValue<TinyLang> for Bool {}

impl fmt::Display for Int {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AbstractValue<TinyLang> for Int {}

impl fmt::Display for Str {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AbstractValue<TinyLang> for Str {}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'(")?;
        let mut padding = "";
        for v in self.0.iter() {
            write!(f, "{}{}", padding, v)?;
            padding = " ";
        }
        write!(f, ")")
    }
}

impl AbstractValue<TinyLang> for List {}

impl fmt::Display for Quote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}", self.0)
    }
}

impl AbstractValue<TinyLang> for Quote {}