femstache 0.1.13

Embrace the feminine mustache to unlock your templating dreams! Or something, I don't know. :3
Documentation
use std::path::PathBuf;

use femstache_eval::{
    Builtin, BuiltinFunction, EvalError, EvalErrorKind, EvalResult, StringValue, Value,
};
use femstache_parser::Span;
use femstache_types::{FunTy, Ty, TyId, TyStore};

pub struct Raw;

impl BuiltinFunction for Raw {
    fn call(&self, args: &[Value]) -> EvalResult<Value> {
        let [value] = &args else {
            // TODO: accurate path and span; error type
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        let Some(s) = value.as_string() else {
            // TODO: accurate path and span
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        Ok(Value::String(match s {
            StringValue::Regular(s) => StringValue::Raw(s.clone()),
            StringValue::Raw(s) => StringValue::Raw(s.clone()),
        }))
    }
}

pub struct ShowInt;

impl BuiltinFunction for ShowInt {
    fn call(&self, args: &[Value]) -> EvalResult<Value> {
        let [value] = &args else {
            // TODO: accurate path and span; error type
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        let Some(i) = value.as_int() else {
            // TODO: accurate path and span
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        Ok(Value::string(i.to_string()))
    }
}

pub struct ShowBool;

impl BuiltinFunction for ShowBool {
    fn call(&self, args: &[Value]) -> EvalResult<Value> {
        let [value] = &args else {
            // TODO: accurate path and span; error type
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        let Some(b) = value.as_bool() else {
            // TODO: accurate path and span
            return Err(EvalError::new(
                EvalErrorKind::InvalidType,
                PathBuf::new(),
                Span::new(0, 0),
            ));
        };
        Ok(Value::string(b.to_string()))
    }
}

pub fn add_builtins(store: &mut TyStore) -> Vec<(String, Builtin)> {
    let mut builtins = Vec::new();
    let raw_id = store.intern(Ty::Fun(FunTy::new([TyId::STRING], TyId::STRING)));
    let show_int_id = store.intern(Ty::Fun(FunTy::new([TyId::INT], TyId::STRING)));
    let show_bool_id = store.intern(Ty::Fun(FunTy::new([TyId::BOOL], TyId::STRING)));
    builtins.push(("raw".to_owned(), Builtin::new(raw_id, Raw)));
    builtins.push(("show_int".to_owned(), Builtin::new(show_int_id, ShowInt)));
    builtins.push(("show_bool".to_owned(), Builtin::new(show_bool_id, ShowBool)));
    builtins
}