use std::sync::Arc;
use imbl::Vector;
use nom::{branch::alt, bytes::complete::tag, character::complete::{char, multispace0}, combinator::opt, sequence::{delimited, preceded}, IResult, Parser};
use crate::{parser::{doc::StofParseError, expr::expr, ident::ident, types::parse_type, whitespace::whitespace}, runtime::{instruction::Instruction, instructions::Base, Type, Val}};
pub fn declare_statement(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, _) = whitespace(input)?;
alt((declare_const_var, declare_mut_var, declare_null_var)).parse(input)
}
pub(self) fn declare_mut_var(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(tag("let"), preceded(multispace0, ident), multispace0).parse(input)?;
let (input, cast_type) = opt(preceded(char(':'), parse_type)).parse(input)?;
let (input, _) = delimited(multispace0, char('='), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
block.push_back(expr);
if let Some(cast_type) = cast_type {
block.push_back(Arc::new(Base::Cast(cast_type.clone())));
block.push_back(Arc::new(Base::DeclareVar(varname.to_string().into(), cast_type)));
} else {
block.push_back(Arc::new(Base::DeclareVar(varname.to_string().into(), Type::Void))); }
Ok((input, block))
}
pub(self) fn declare_const_var(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(tag("const"), preceded(multispace0, ident), multispace0).parse(input)?;
let (input, cast_type) = opt(preceded(char(':'), parse_type)).parse(input)?;
let (input, _) = delimited(multispace0, char('='), multispace0).parse(input)?;
let (input, expr) = expr(input)?;
let mut block = Vector::default();
block.push_back(expr);
if let Some(cast_type) = cast_type {
block.push_back(Arc::new(Base::Cast(cast_type.clone())));
block.push_back(Arc::new(Base::DeclareConstVar(varname.to_string().into(), cast_type)));
} else {
block.push_back(Arc::new(Base::DeclareConstVar(varname.to_string().into(), Type::Void))); }
Ok((input, block))
}
pub(self) fn declare_null_var(input: &str) -> IResult<&str, Vector<Arc<dyn Instruction>>, StofParseError> {
let (input, varname) = delimited(tag("let"), preceded(multispace0, ident), multispace0).parse(input)?;
let (input, cast_type) = opt(preceded(char(':'), parse_type)).parse(input)?;
let mut block = Vector::default();
block.push_back(Arc::new(Base::Literal(Val::Null)) as Arc<dyn Instruction>);
if let Some(cast_type) = cast_type {
block.push_back(Arc::new(Base::Cast(cast_type.clone())));
block.push_back(Arc::new(Base::DeclareVar(varname.to_string().into(), cast_type)));
} else {
block.push_back(Arc::new(Base::DeclareVar(varname.to_string().into(), Type::Void))); }
Ok((input, block))
}