kari 0.1.0

An embeddable programming language, writting in and for Rust
Documentation
use std::{
    borrow::Cow,
    collections::HashMap,
    fs::File,
    io::{
        self,
        Cursor,
    },
};

use crate::{
    builtins::builtins,
    call_stack::{
        CallStack,
        StackFrame,
    },
    context::{
        self,
        Context,
    },
    data::{
        expression::Expression,
        functions::{
            self,
            DefineError,
            Functions,
            Scope,
        },
        stack::Stack,
        token::Span,
        types::Type,
        value::{
            self,
            Value as _,
        },
    },
    function::{
        Builtin,
        Function,
    },
    interpreter::{
        error::Error,
        stream::Stream,
    },
    pipeline::{
        self,
        Stage as _,
        parser,
    },
};


pub struct Evaluator<Host> {
    streams: HashMap<String, Box<dyn Stream>>,
    stdout:  Box<dyn io::Write>,
    stderr:  Box<dyn io::Write>,

    functions:  Functions<Function<Host>>,
    stack:      Stack,
    call_stack: CallStack,
}

impl<Host> Evaluator<Host> {
    pub fn new(
        stdout: Box<dyn io::Write>,
        stderr: Box<dyn io::Write>,
    )
        -> Self
    {
        Self {
            streams: HashMap::new(),
            stdout,
            stderr,

            functions:  Functions::new(),
            stack:      Stack::new(),
            call_stack: CallStack::new(),
        }
    }

    pub fn with_default_builtins(mut self) -> Self {
        builtins(&mut self.functions);
        self
    }

    pub fn with_default_prelude(mut self, host: &mut Host)
        -> Result<Self, Error>
    {
        let     name    = "<prelude>";
        let mut prelude = Cursor::new(
            &include_bytes!("../../kr/src/prelude.kr")[..],
        );

        let prelude_pipeline = pipeline::new(
            name.into(),
            &mut prelude,
        );

        self.evaluate_expressions(
            host,
            self.functions.root_scope(),
            prelude_pipeline,
        )?;

        // We panic on errors in the prelude itself, but errors in other modules
        // might still produce stack traces with spans that refer to the
        // prelude.
        self.streams.insert(
            name.into(),
            Box::new(prelude),
        );

        Ok(self)
    }

    pub fn with_builtin(mut self,
        name:    &str,
        args:    &[&'static dyn Type],
        builtin: Builtin<Host>,
    ) -> Result<Self, DefineError> {
        self.functions.define(
            self.functions.root_scope(),
            String::from(name),
            args,
            Function::Builtin(builtin),
        )?;
        Ok(self)

    }

    pub fn run(mut self,
            host:    &mut Host,
            name:    Cow<str>,
        mut program: Box<dyn Stream>,
    )
        -> Result<Vec<value::Any>, ()>
    {
        let pipeline = pipeline::new(
            name.clone().into_owned(),
            &mut program,
        );

        let result = self.evaluate_expressions(
            host,
            self.functions.root_scope(),
            pipeline,
        );
        if let Err(error) = result {
            self.streams.insert(
                name.into_owned(),
                program,
            );

            if let Err(error) =
                error.print(&mut self.streams, &mut self.stderr)
            {
                print!("Error printing error: {}\n", error)
            }

            return Err(());
        }

        Ok(self.stack.into_vec())
    }

    fn evaluate_expressions<Parser>(&mut self,
            host:   &mut Host,
            scope:  Scope,
        mut parser: Parser,
    )
        -> Result<(), Error>
        where Parser: pipeline::Stage<Item=Expression, Error=parser::Error>
    {
        loop {
            let expression = match parser.next() {
                Ok(expression) => {
                    expression
                }
                Err(parser::Error::EndOfStream) => {
                    return Ok(());
                }
                Err(error) => {
                    return Err(
                        Error {
                            kind:       error.into(),
                            call_stack: self.call_stack.clone(),
                        }
                    );
                }
            };

            let list_scope = self.functions.new_scope(scope, "list");

            let result = self.evaluate_value(
                host,
                scope,
                value::Any::from_expression(
                    expression,
                    list_scope,
                ),
            );
            if let Err(error) = result {
                return Err(
                    Error {
                        kind:       error.into(),
                        call_stack: self.call_stack.clone(),
                    }
                );
            }
        }
    }
}

impl<Host> Context<Host> for Evaluator<Host> {
    fn functions(&mut self) -> &mut Functions<Function<Host>> {
        &mut self.functions
    }

    fn stack(&mut self) -> &mut Stack {
        &mut self.stack
    }

    fn call_stack(&mut self) -> &mut CallStack {
        &mut self.call_stack
    }

    fn output(&mut self) -> &mut dyn io::Write {
        &mut self.stdout
    }

    fn load(&mut self, name: value::String, scope: Scope)
        -> Result<value::List, context::Error>
    {
        let module_scope = self.functions.new_scope(scope, name.inner.clone());

        let     path   = format!("kr/src/{}.kr", name.inner);
        let mut stream = File::open(&path)?;

        let mut parser      = pipeline::new(path.clone(), &mut stream);
        let mut expressions = Vec::new();

        loop {
            match parser.next() {
                Ok(expression)                  => expressions.push(expression),
                Err(parser::Error::EndOfStream) => break,
                Err(error)                      => return Err(error.into()),
            }
        }

        self.streams.insert(path, Box::new(stream));

        let start = expressions
            .first()
            .map(|expression| expression.span.clone())
            .unwrap_or(Span::default());
        let end = expressions
            .last()
            .map(|expression| expression.span.clone())
            .unwrap_or(Span::default());

        Ok(
            value::List::new(
                value::ListInner::from_expressions(
                    expressions,
                    module_scope,
                ),
                start.merge(&end),
            )
        )
    }

    fn evaluate_value(&mut self,
        host:  &mut Host,
        scope: Scope,
        value: value::Any,
    )
        -> Result<(), context::Error>
    {
        if let value::Kind::Word(word) = value.kind {
            self.call_stack.frames.push(
                StackFrame {
                    scope,
                    span: value.span,
                }
            );

            match self.functions.get(scope, &word, &self.stack) {
                Ok(f) => {
                    match f {
                        Function::Builtin(f) => {
                            f(
                                host,
                                self,
                                scope,
                            )?;
                        }
                        Function::UserDefined { body } => {
                            self.evaluate_list(
                                host,
                                body,
                            )?;
                        }
                    }
                }
                Err(functions::GetError { candidates, scope, .. }) => {
                    return Err(
                        context::Error::FunctionNotFound {
                            name:  word,
                            stack: self.stack.clone(),
                            candidates,
                            scope: scope,
                        }
                    );
                }
            }

            self.call_stack.frames.pop();
        }
        else {
            self.stack.push::<value::Any>(value);
        }

        Ok(())
    }

    fn evaluate_list(&mut self,
        host: &mut Host,
        list: value::List,
    )
        -> Result<(), context::Error>
    {
        let scope = list.inner.scope;

        for expr in list {
            self.evaluate_value(
                host,
                scope,
                expr,
            )?;
        }

        Ok(())
    }
}