//! # masl_parser
//!
//! MASL source parser built on the PEST PEG parser generator.
//!
//! Produces an `masl_ast::Document` from raw `.mdk` source text.
//!
//! See RFC-0003 — Grammar and RFC-0007 — Compiler Architecture.

#![allow(clippy::result_large_err)]

pub mod error;
pub mod grammar;
pub mod lower;

use pest::Parser;
use pest::error::InputLocation;

use masl_ast::Document;
use masl_diagnostics::diagnostic::Diagnostic;
use masl_diagnostics::span::Span;

use grammar::{MaslParser, Rule};

/// Parse a MASL source string into an AST Document.
///
/// Returns either a fully parsed `Document` or a vector of parse diagnostics.
pub fn parse(source: &str) -> Result<Document, Vec<Diagnostic>> {
    match MaslParser::parse(Rule::document, source) {
        Ok(mut pairs) => {
            let doc_pair = pairs.next().unwrap();
            match lower::lower_document(doc_pair) {
                Ok(doc) => Ok(doc),
                Err(diag) => Err(vec![diag]),
            }
        }
        Err(e) => {
            // Map PEST error to Diagnostic E0100/E0101
            let (line, col) = match e.line_col {
                pest::error::LineColLocation::Pos((l, c)) => (l, c),
                pest::error::LineColLocation::Span((l, c), _) => (l, c),
            };

            let start = match e.location {
                InputLocation::Pos(pos) => pos,
                InputLocation::Span((start, _)) => start,
            };
            let end = match e.location {
                InputLocation::Pos(pos) => pos,
                InputLocation::Span((_, end)) => end,
            };

            let span = Span::new(start, end, line, col);
            let diagnostic = Diagnostic::error("E0100", format!("{}", e), span);
            Err(vec![diagnostic])
        }
    }
}
