//! cassiopeia file format mod gen; pub(crate) mod ir; mod lexer; mod parser; pub(crate) use lexer::{LineLexer, LineToken, Token}; pub(crate) use parser::LineCfg; use crate::{ error::{ParseError, ParseResult}, TimeFile, }; use ir::{IrItem, IrStream}; use std::{ fs::{File, OpenOptions}, io::{Read, Write}, }; /// A crate internal representation of the IR stream and timefile #[derive(Default)] pub(crate) struct ParseOutput { pub(crate) ir: IrStream, pub(crate) tf: TimeFile, } impl ParseOutput { fn append(mut self, ir: IrItem) -> ParseResult { self.tf.append(ir.clone())?; self.ir.push(ir); Ok(self) } } /// Load a file from disk and parse it into a /// [`TimeFile`](crate::TimeFile) pub(crate) fn load_file(path: &str) -> ParseResult { // Load the raw file contents let mut f = File::open(path)?; let mut content = String::new(); f.read_to_string(&mut content)?; // Split the file by lines - .cass is a line based format let mut lines: Vec = content.split("\n").map(|l| l.to_owned()).collect(); // Build an iterator over parsed lines let parsed = lines .iter_mut() .map(|line| lexer::lex(line)) .map(|lex| parser::parse(lex)); // Generate the IR from parse output, then build the timefile ir::generate_ir(parsed) .into_iter() .fold(Ok(ParseOutput::default()), |out, ir| match out { Ok(mut out) => out.append(ir), e @ Err(_) => e, }) } /// Write a file with the updated IR stream pub(crate) fn write_file(path: &str, ir: &mut IrStream) -> ParseResult<()> { ir::update_header(ir); let mut lines = ir.into_iter().map(|ir| gen::line(ir)).collect::>(); lines.insert(0, gen::head_comment()); // let mut f = OpenOptions::new() // .write(true) // .create(true) // .truncate(true) // .open(path) // .ok()?; // f.write_all(lines.join("\n").as_bytes()).ok()?; Ok(()) }