chibi 0.1.0

Name reserved for a programming language project.
Documentation
use std::{borrow::Cow, collections::HashMap};

use serde::Serialize;
use parser::parse;

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize, Clone)]

pub enum Literal<'i> {
    Int(i32),
    Float(f32),
    Char(char),
    Str(Cow<'i, str>),
    Vec(Vec<Literal<'i>>),
}

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Value<'i> {
    Literal(Literal<'i>),
}

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Expr<'i> {
    Literal(Literal<'i>),
    Name(&'i str),
    None,
}

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Statement<'i> {
    Let(&'i str, Expr<'i>),
    Comment(&'i str),
    Nothing,
    Endline,
    Eof,
}

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Inst<'i> {
    #[serde(borrow = "'i")]
    Expr(Expr<'i>),
    Statement(Statement<'i>),
}

pub struct Scope<'i> {
    pub vars: HashMap<&'i str, Value<'i>>
}

#[allow(clippy::new_without_default)]
impl<'i> Scope<'i> {
    pub fn new() -> Scope<'i> {
        Scope { vars: HashMap::new() }
    }
    
    pub fn add_var(&'i mut self, name: &'i str, value: Value<'i>) {
        self.vars.insert(name, value);
    }
}

fn value_from_expr<'i>(e: &'i Expr<'i>, scope: &'i Scope) -> Value<'i> {
    match e {
        Expr::Literal(l) => todo!(),
        Expr::Name(n) => todo!(),
        Expr::None => todo!(),
    }
}

peg::parser! {
    pub grammar parser() for str {
        use peg::ParseLiteral;

        // Basics
        pub rule any() = [_]
        pub rule any_except(exc: &str) -> char = !##parse_string_literal(exc) c:[_] { c }
        pub rule between(start: &str, end: &str) -> &'input str = ##parse_string_literal(start) n:$((!##parse_string_literal(end) [_])*) ##parse_string_literal(end) { n }
        pub rule between_min(start: &str, end: &str) -> &'input str = ##parse_string_literal(start) n:$((!##parse_string_literal(end) [_])+) ##parse_string_literal(end) { n }
        pub rule endline() -> Statement<'input> = "\n" {Statement::Endline}
        pub rule eof() -> Statement<'input> = !any() { Statement::Eof }
        pub rule line_comment() -> Statement<'input> = "//" n:$([^'\n']*) { Statement::Comment(n) }
        pub rule block_comment() -> Statement<'input> = n:between("/*", "*/") { Statement::Comment(n) }
        pub rule comment() -> Statement<'input> = line_comment() / block_comment()
        pub rule whitespace() -> Statement<'input> = [' ' | '\t'] { Statement::Nothing }
        pub rule nothing() -> Statement<'input> = comment() / whitespace() / endline()
        rule _ = nothing()+
        
        // Values
        pub rule number() -> Literal<'input> = n:$(['0'..='9']+) {? n.parse::<i32>().or(Err("i32")).map(Literal::Int) }
        pub rule float() -> Literal<'input> = n:$(number() "." number()) {? n.parse::<f32>().or(Err("f32")).map(Literal::Float) }
        pub rule char() -> Literal<'input> = "'" c:[_] "'" { Literal::Char(c) }
        pub rule str() -> Literal<'input> = s:between("\"", "\"") { Literal::Str(Cow::from(s)) }
        pub rule ident() -> &'input str = i:$(("_"['0'..='9']/[^ ' ' | '\n' | '\t' | '!' | '=' | '-' | '+' | '*' | '/' | '&' | '|' | ':' | '0'..='9'])+)
        pub rule literal() -> Literal<'input> = float() / number() / char() / str()
        pub rule name() -> Expr<'input> = n:ident() { Expr::Name(n) }
        pub rule type_annotation() -> Option<&'input str> = t:(":" _ t:ident() { t })? { t }
        // Statements
        pub rule _let(scope: &mut Scope<'input>) -> Statement<'input> = "let" _ n:$name() _ t:type_annotation() _ "=" _ e:expr(scope) {
            if let Some(t) = t {
                // TODO! Type checking on declaration
                todo!()
            }
            
            //let val = value_from_expr(&e, scope);
            //scope.add_var(n, val);
            //scope.add_var(n, val);
            Statement::Let(n, e)
        }
        // Groups
        pub rule expr(scope: &mut Scope) -> Expr<'input> = l:literal() { Expr::Literal(l) } / name()
        pub rule statement(scope: &mut Scope<'input>) -> Inst<'input> = s:(_let(scope)) { Inst::Statement(s) }
        pub rule instruction(scope: &mut Scope<'input>) -> Inst<'input> = statement(scope) / e:expr(scope) { Inst::Expr(e)}

        
        pub rule parse(scope: &mut Scope<'input>) -> Vec<Inst<'input>> = e:(instruction(scope) ** "\n") _* { e }
    }
}