use core::panic; use crate::{ builtins::{TYPE_FLOAT, TYPE_INTEGER, TYPE_STRING}, error::Errors, namespace::{command::Command, r#type::Type, GlobalNamespace}, syntax::{CommandPart, CommandPartKind, PipelineElement, PipelineElementKind}, Span, }; #[allow(dead_code, reason = "will be used later")] #[derive(Debug)] pub struct Expr<'a> { kind: ExprKind<'a>, span: Span, } #[derive(Debug)] pub enum ExprKind<'a> { Command { command: Command<'a>, args: Vec>, }, Literal(LiteralKind), } #[derive(Debug)] pub enum LiteralKind { Int(i64), Float(f64), String(String), } impl LiteralKind { #[allow( clippy::unwrap_used, reason = "these are fetched by type name constants used for keeping names consistent in codebase, which cannot be None" )] pub fn get_type<'a>(&self, ns: &'a GlobalNamespace) -> Type<'a> { match self { LiteralKind::Int(_) => ns.get_type_by_name(TYPE_INTEGER).unwrap(), LiteralKind::Float(_) => ns.get_type_by_name(TYPE_FLOAT).unwrap(), LiteralKind::String(_) => ns.get_type_by_name(TYPE_STRING).unwrap(), } } } pub fn into_typed_repr( ns: &GlobalNamespace, syntax: Vec, ) -> Result, Errors> { let mut res = Vec::new(); let mut errs = Vec::new(); for item in syntax { let PipelineElement { kind, span } = item; match kind { PipelineElementKind::Command(c) => { if c.len() == 1 { let CommandPart { kind, .. } = &c[0]; res.push(Expr { kind: match kind { CommandPartKind::Word(val) => ExprKind::Command { command: { let Some(c) = ns.get_command_by_name(val) else { errs.push(span); continue; }; c }, args: Vec::new(), }, CommandPartKind::Integer(val) => { ExprKind::Literal(LiteralKind::Int(*val)) } CommandPartKind::Float(val) => { ExprKind::Literal(LiteralKind::Float(*val)) } CommandPartKind::String(val) => { ExprKind::Literal(LiteralKind::String(val.clone())) } }, span, }); } else { let Some(CommandPart { kind: CommandPartKind::Word(name), span, }) = c.first() else { panic!("tried conversion to typed representation with invalid syntax") }; res.push(Expr { kind: ExprKind::Command { command: { let Some(c) = ns.get_command_by_name(name) else { errs.push(span.clone()); continue; }; c }, args: c .iter() .skip(1) .map(|CommandPart { kind, span }| Expr { kind: ExprKind::Literal(match kind { CommandPartKind::String(val) | CommandPartKind::Word(val) => { LiteralKind::String(val.to_string()) } CommandPartKind::Integer(val) => LiteralKind::Int(*val), CommandPartKind::Float(val) => LiteralKind::Float(*val), }), span: span.clone(), }) .collect(), }, span: span.clone(), }); } } PipelineElementKind::Pipe => {} } } if errs.is_empty() { Ok(res) } else { Err(Errors::new(crate::error::ErrorKind::CommandNotFound, errs)) } }