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;
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()+
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 }
pub rule _let(scope: &mut Scope<'input>) -> Statement<'input> = "let" _ n:$name() _ t:type_annotation() _ "=" _ e:expr(scope) {
if let Some(t) = t {
todo!()
}
Statement::Let(n, e)
}
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 }
}
}