luna-lib 1.3.0

a light weight interpreted programming language
Documentation
pub mod lang;
pub mod luna_impl;
#[cfg(test)]
pub mod tests;

use lang::{
    code::Closure,
    tokens::Token,
    value::{Function, Value},
};
use luna_impl::{
    compiler::{Compilable, Compiler},
    interpreter::Interpreter,
    lexer::Lexer,
    parser::{Parsable, ParseError},
    position::{Located, PathLocated},
};
use std::{cell::RefCell, env, error::Error, fmt::Display, rc::Rc};

pub fn lex_str(text: &str) -> Result<Vec<Located<Token>>, Located<Box<dyn Error>>> {
    Lexer::from(text)
        .lex()
        .map_err(|err| err.map(|err| err.into()))
}
pub fn parse_str<A: Parsable>(text: &str) -> Result<Located<A>, Located<Box<dyn Error>>> {
    let mut lexer = lex_str(text)?.into_iter().peekable();
    let ast = A::parse(&mut lexer).map_err(|err| err.map(|err| err.into()))?;
    if let Some(Located { value: token, pos }) = lexer.next() {
        return Err(Located::new(ParseError::UnexpectedToken(token).into(), pos));
    }
    Ok(ast)
}
pub fn compile_str<A: Parsable>(
    text: &str,
    path: Option<&str>,
) -> Result<Rc<RefCell<Closure>>, Located<Box<dyn Error>>>
where
    Located<A>: Compilable<Output = Rc<RefCell<Closure>>>,
{
    let ast = parse_str::<A>(text)?;
    let closure = ast.compile(&mut Compiler {
        path: path.map(|s| s.to_string()),
        ..Default::default()
    })?;
    Ok(closure)
}
pub fn run_str<A: Parsable>(
    text: &str,
    path: Option<&str>,
) -> Result<Option<Value>, PathLocated<Box<dyn Error>>>
where
    Located<A>: Compilable<Output = Rc<RefCell<Closure>>>,
{
    let closure = compile_str(text, path).map_err(|err| {
        err.with_path(
            path.map(|path| path.to_string())
                .unwrap_or("<input>".to_string()),
        )
    })?;
    let function = Rc::new(Function {
        closure,
        upvalues: vec![],
    });
    let mut interpreter = Interpreter::default().with_global_path(env::var("LUNA_PATH").ok());
    interpreter.call(&function, vec![], None);
    interpreter.run().map_err(|err| {
        err.map(|err| err.into())
            .with_path(interpreter.path().unwrap_or("<input>".to_string()))
    })
}

#[macro_export]
macro_rules! int {
    ($v:literal) => {
        Value::Int($v.into())
    };
}
#[macro_export]
macro_rules! float {
    ($v:literal) => {
        Value::Float($v.into())
    };
}
#[macro_export]
macro_rules! bool {
    ($v:literal) => {
        Value::Bool($v.into())
    };
}
#[macro_export]
macro_rules! char {
    ($v:literal) => {
        Value::Char($v.into())
    };
}
#[macro_export]
macro_rules! string {
    ($v:literal) => {
        Value::String($v.to_string())
    };
}
#[macro_export]
macro_rules! vector {
    [$($v:literal),*] => {
        Value::Vector(Rc::new(RefCell::new(vec![$($v.into()),*])))
    };
    ($v:expr) => {
        Value::Vector(Rc::new(RefCell::new($v.into())))
    };
}
#[macro_export]
macro_rules! object {
    {$($k:literal = $v:expr),*} => {
        {
            #[allow(unused_variables, unused_mut)]
            let mut map = HashMap::new();
            $(
                map.insert($k.into(), $v.into());
            ) *
            Value::Object(Rc::new(RefCell::new(Object::new(map))))
        }
    };
    ($v:expr) => {
        Value::Object(Rc::new(RefCell::new(Object::new($v))))
    };
}
#[macro_export]
macro_rules! function {
    ($name:ident) => {
        Value::Function(FunctionKind::UserFunction(Rc::new($name)))
    };
}
#[macro_export]
macro_rules! set_field {
    ($map:ident . $field:literal = $value:expr) => {
        $map.insert($field.to_string(), Rc::new(RefCell::new($value)));
    };
    ($map:ident . $field:ident = $value:expr) => {
        $map.insert($field.to_string(), Rc::new(RefCell::new($value)));
    };
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExpectedType {
    pub idx: usize,
    pub expected: &'static str,
    pub got: &'static str,
}
impl Display for ExpectedType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "expected {} for argument #{}, got {}",
            self.expected, self.idx, self.got
        )
    }
}
impl Error for ExpectedType {}
#[derive(Debug, Clone, PartialEq)]
pub struct ExpectedTypes {
    pub idx: usize,
    pub expected: Vec<&'static str>,
    pub got: &'static str,
}
impl Display for ExpectedTypes {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "expected {} for argument #{}, got {}",
            self.expected.join("/"),
            self.idx,
            self.got
        )
    }
}
impl Error for ExpectedTypes {}
#[macro_export]
macro_rules! typed {
    ($args:ident) => {{
        let (_, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        arg
    }};
    ($args:ident : $type:ident) => {{
        let (idx, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        if let Value::$type(value) = arg {
            value
        } else {
            return Err(ExpectedType {
                idx,
                expected: Value::$type(Default::default()).typ(),
                got: arg.typ(),
            }
            .into());
        }
    }};
    ($args:ident : $type:ident ?) => {{
        let (idx, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        if arg == Value::default() {
            None
        } else {
            if let Value::$type(value) = arg {
                Some(value)
            } else {
                return Err(ExpectedType {
                    idx,
                    expected: Value::$type(Default::default()).typ(),
                    got: arg.typ(),
                }
                .into());
            }
        }
    }};
    ($args:ident : $type:ident $param:ident => $value:expr) => {{
        let (idx, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        if let Value::$type($param) = arg {
            $value
        } else {
            return Err(ExpectedType {
                idx,
                expected: Value::$type(Default::default()).typ(),
                got: arg.typ(),
            }
            .into());
        }
    }};
    ($args:ident : $type:ident ? $param:ident => $value:expr) => {{
        let (idx, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        if arg == Value::default() {
            None
        } else {
            if let Value::$type($param) = arg {
                Some($value)
            } else {
                return Err(ExpectedType {
                    idx,
                    expected: Value::$type(Default::default()).typ(),
                    got: arg.typ(),
                }
                .into());
            }
        }
    }};
}
#[macro_export]
macro_rules! option {
    ($args:ident : $($type:ident => $value:ident $body:block),+) => {{
        let (idx, arg) = $args.next().unwrap_or(($args.len(), Value::default()));
        match arg {
            $(
                Value::$type($value) => $body,
            ) +
            arg => {
                return Err(ExpectedTypes {
                    idx,
                    expected: vec![$(Value::$type(Default::default()).typ()),+],
                    got: arg.typ(),
                }
                .into())
            }
        }
    }};
}
#[macro_export]
macro_rules! userobject {
    (
        $name:ident : $typ_name:literal ;
        $self:ident
        $(static ($fn_self:ident, $fn_args:ident) { $(
            $fn_name:ident : $fn_literal_name:literal $fn_body:block
        ) *})?
        $(mut ($fn_mut_self:ident, $fn_mut_args:ident) { $(
            $fn_mut_name:ident : $fn_mut_literal_name:literal $fn_mut_body:block
        ) *})?
    ) => {
        impl UserObject for $name {
            fn typ(&self) -> &'static str {
                $typ_name
            }
            fn get(&$self, key: &str) -> Option<Value> {
                match key {
                    $(
                        $(
                            $fn_literal_name => Some(Value::Function(FunctionKind::UserFunction(Rc::new(
                                Box::new(Self::$fn_name),
                            )))),
                        )*
                    )?
                    $(
                        $(
                            $fn_mut_literal_name => Some(Value::Function(FunctionKind::UserFunction(Rc::new(
                                Box::new(Self::$fn_mut_name),
                            )))),
                        )*
                    )?
                    _ => None,
                }
            }
            $(
                #[allow(unused_variables)]
                fn call(&$fn_self, key: &str, $fn_args: Vec<Value>) -> Result<Value, Box<dyn Error>> {
                    match key {
                        $(
                            $fn_literal_name => $fn_body,
                        )+
                        _ => Err(Box::new(UserObjectError::CannotCallNull))
                    }
                }
            )?
            $(
                #[allow(unused_variables)]
                fn call_mut(&mut $fn_mut_self, key: &str, $fn_mut_args: Vec<Value>) -> Result<Value, Box<dyn Error>> {
                    match key {
                        $(
                            $fn_mut_literal_name => $fn_mut_body,
                        )+
                        _ => Err(Box::new(UserObjectError::CannotCallNull))
                    }
                }
            )?
        }
        impl $name {
            $(
                $(
                    pub fn $fn_name(_: &mut Interpreter, mut $fn_args: Vec<Value>) -> Result<Value, Box<dyn Error>> {
                        let Some(_self) = $fn_args.first().cloned() else {
                            return Err(Box::new(UserObjectError::ExpectedSelf("null")));
                        };
                        $fn_args.remove(0);
                        if let Value::UserObject(_self) = _self {
                            let mut _self = _self.borrow_mut();
                            _self.call($fn_literal_name, $fn_args)
                        } else {
                            Err(Box::new(UserObjectError::ExpectedSelf(_self.typ())))
                        }
                    }
                ) *
            )?
            $(
                $(
                    pub fn $fn_mut_name(_: &mut Interpreter, mut $fn_mut_args: Vec<Value>) -> Result<Value, Box<dyn Error>> {
                        let Some(_self) = $fn_mut_args.first().cloned() else {
                            return Err(Box::new(UserObjectError::ExpectedSelf("null")));
                        };
                        $fn_mut_args.remove(0);
                        if let Value::UserObject(_self) = _self {
                            let mut _self = _self.borrow_mut();
                            _self.call_mut($fn_mut_literal_name, $fn_mut_args)
                        } else {
                            Err(Box::new(UserObjectError::ExpectedSelf(_self.typ())))
                        }
                    }
                ) *
            )?
        }
    };
}