ksl 0.1.7

KSL core library and interpreter
Documentation
//! # ksl::eval::sentence
//!
//! Defines a function that evaluates a KSL sentence.

use crate::{
    Environment,
    eval::pair::{PairType, eval_pair},
    token::{Token, TokenType},
    value::Value,
};

/// Evaluation of a KSL sentence.
pub(crate) fn eval_sentence(tokens: &[Token], env: &Environment) -> Option<Value> {
    let mut current_token: usize = 0;
    if let Some(token) = tokens.get(current_token) {
        match &token.value {
            TokenType::Atom(a) => {
                if let Some(tok) = tokens.get(current_token + 1) {
                    eprintln!(
                        concat!(
                            "Error[ksl::eval::eval_sentence]: ",
                            "Unknown token `{:?}` at ({}, {})."
                        ),
                        tok.value, tok.position.0.0, tok.position.0.1
                    );
                    return None;
                } else {
                    return Some(Value::Atom(a.clone()));
                }
            }
            TokenType::String(s) => {
                if let Some(tok) = tokens.get(current_token + 1) {
                    eprintln!(
                        concat!(
                            "Error[ksl::eval::eval_sentence]: ",
                            "Unknown token `{:?}` at ({}, {})."
                        ),
                        tok.value, tok.position.0.0, tok.position.0.1
                    );
                    return None;
                } else {
                    return Some(Value::String(s.clone()));
                }
            }
            TokenType::Char(c) => {
                if let Some(tok) = tokens.get(current_token + 1) {
                    eprintln!(
                        concat!(
                            "Error[ksl::eval::eval_sentence]: ",
                            "Unknown token `{:?}` at ({}, {})."
                        ),
                        tok.value, tok.position.0.0, tok.position.0.1
                    );
                    return None;
                } else {
                    return Some(Value::String(String::from(*c as char)));
                }
            }
            TokenType::Number(n) => {
                if let Some(tok) = tokens.get(current_token + 1) {
                    eprintln!(
                        concat!(
                            "Error[ksl::eval::eval_sentence]: ",
                            "Unknown token `{:?}` at ({}, {})."
                        ),
                        tok.value, tok.position.0.0, tok.position.0.1
                    );
                    return None;
                } else {
                    return Some(Value::Number(n.clone()));
                }
            }
            TokenType::Identity(id) => {
                if let Some(tok) = tokens.get(current_token + 1) {
                    current_token += 1;
                    match tok.value {
                        TokenType::FuncListOpen => {
                            let arguments = eval_pair(&tokens[(current_token + 1)..], env, PairType::Function);
                            if let Some((args, bias)) = arguments {
                                return if (current_token + bias + 1) < tokens.len() {
                                    eprintln!(
                                        concat!(
                                            "Error[ksl::eval::eval_sentence]: ",
                                            "Invalid token `{:?}` at ({}, {})."
                                        ),
                                        tokens[current_token + bias + 1].value,
                                        tokens[current_token + bias + 1].position.0.0,
                                        tokens[current_token + bias + 1].position.0.1
                                    );
                                    None
                                } else {
                                    Some(Value::Apply(args, Box::new(Value::Identity(id.clone()))))
                                };
                            } else {
                                eprintln!(
                                    concat!(
                                        "Error[ksl::eval::eval_sentence]: ",
                                        "Unable to get the arguments of function `{}` at ({}, {})."
                                    ),
                                    id, tok.position.0.0, tok.position.0.1
                                );
                                return None;
                            }
                        }
                        _ => {
                            eprintln!(
                                concat!(
                                    "Error[ksl::eval::eval_sentence]: ",
                                    "Unknown token `{:?}` at ({}, {})."
                                ),
                                tok.value, tok.position.0.0, tok.position.0.1
                            );
                            return None;
                        }
                    }
                } else {
                    if let Some(v) = env.get(id) {
                        Some(v.clone())
                    } else {
                        eprintln!(
                            concat!("Error[ksl::eval::eval_sentence]: ", "Unknown symbol `{}`."),
                            id
                        );
                        None
                    }
                }
            }
            TokenType::ListOpen => {
                let contents = eval_pair(&tokens[(current_token + 1)..], env, PairType::List);
                if let Some((vals, bias)) = contents {
                    return if (current_token + bias + 1) < tokens.len() {
                        eprintln!(
                            concat!(
                                "Error[ksl::eval::eval_sentence]: ",
                                "Invalid token `{:?}` at ({}, {})."
                            ),
                            tokens[current_token + bias + 1].value,
                            tokens[current_token + bias + 1].position.0.0,
                            tokens[current_token + bias + 1].position.0.1
                        );
                        None
                    } else {
                        Some(Value::List(vals))
                    };
                } else {
                    return None;
                }
            }
            _val => {
                eprintln!(
                    concat!(
                        "Error[ksl::eval::eval_sentence]: ",
                        "Unknown token `{:?}` at ({}, {})."
                    ),
                    token.value, token.position.0.0, token.position.0.1
                );
                return None;
            }
        }
    } else {
        None
    }
}