lark-parser 0.1.0

Parser for the Lark language.
use crate::parser::Parser;
use crate::syntax::delimited::Delimited;
use crate::syntax::entity::ErrorParsedEntity;
use crate::syntax::entity::LazyParsedEntity;
use crate::syntax::entity::LazyParsedEntityDatabase;
use crate::syntax::fn_body;
use crate::syntax::guard::Guard;
use crate::syntax::identifier::SpannedGlobalIdentifier;
use crate::syntax::list::CommaList;
use crate::syntax::matched::Matched;
use crate::syntax::matched::ParsedMatch;
use crate::syntax::member::{Field, ParsedField};
use crate::syntax::sigil::{Curlies, Parentheses, RightArrow};
use crate::syntax::skip_newline::SkipNewline;
use crate::syntax::type_reference::ParsedTypeReference;
use crate::syntax::type_reference::TypeReference;
use crate::syntax::Syntax;
use lark_collections::Seq;
use lark_debug_derive::DebugWith;
use lark_entity::Entity;
use lark_error::ErrorReported;
use lark_error::ResultExt;
use lark_error::WithError;
use lark_hir as hir;
use lark_intern::Untern;
use lark_span::FileName;
use lark_span::Spanned;
use lark_string::GlobalIdentifier;
use lark_ty as ty;
use lark_ty::declaration::Declaration;

#[derive(DebugWith)]
pub struct FunctionSignature;

#[derive(Clone, DebugWith)]
pub struct ParsedFunctionSignature {
    pub parameters: Seq<Spanned<ParsedField, FileName>>,
    pub return_type: ParsedTypeReference,
    pub body: Result<Spanned<ParsedMatch, FileName>, ErrorReported>,
}

impl Syntax<'parse> for FunctionSignature {
    type Data = ParsedFunctionSignature;

    fn test(&mut self, parser: &Parser<'_>) -> bool {
        parser.test(SpannedGlobalIdentifier)
    }

    fn expect(&mut self, parser: &mut Parser<'_>) -> Result<Self::Data, ErrorReported> {
        let parameters = parser
            .expect(SkipNewline(Delimited(Parentheses, CommaList(Field))))
            .unwrap_or_else(|ErrorReported(_)| Seq::default());

        let return_type = match parser
            .parse_if_present(SkipNewline(Guard(RightArrow, SkipNewline(TypeReference))))
        {
            Some(ty) => ty.unwrap_or_error_sentinel(&*parser),
            None => ParsedTypeReference::Elided(parser.elided_span()),
        };

        let body = parser.expect(SkipNewline(Matched(Curlies)));

        Ok(ParsedFunctionSignature {
            parameters,
            return_type,
            body,
        })
    }
}

impl ParsedFunctionSignature {
    pub fn parse_signature(
        &self,
        entity: Entity,
        db: &dyn LazyParsedEntityDatabase,
        self_ty: Option<ty::Ty<Declaration>>,
    ) -> WithError<Result<ty::Signature<Declaration>, ErrorReported>> {
        let mut errors = vec![];

        let inputs: Seq<_> = self_ty
            .into_iter()
            .chain(self.parameters.iter().map(|p| {
                p.ty.parse_type(entity, db)
                    .accumulate_errors_into(&mut errors)
            }))
            .collect();

        let output = self
            .return_type
            .parse_type(entity, db)
            .accumulate_errors_into(&mut errors);

        WithError {
            value: Ok(ty::Signature { inputs, output }),
            errors,
        }
    }

    pub fn parse_fn_body(
        &self,
        entity: Entity,
        db: &dyn LazyParsedEntityDatabase,
        self_argument: Option<Spanned<GlobalIdentifier, FileName>>,
    ) -> WithError<hir::FnBody> {
        match self.body {
            Err(err) => ErrorParsedEntity { err }.parse_fn_body(entity, db),

            Ok(Spanned {
                span: _,
                value:
                    ParsedMatch {
                        start_token,
                        end_token,
                    },
            }) => {
                let file_name = entity.untern(&db).file_name(&db).unwrap();
                let input = db.file_text(file_name);
                let tokens = db
                    .file_tokens(file_name)
                    .into_value()
                    .extract(start_token..end_token);
                let entity_macro_definitions = crate::macro_definitions(&db, entity);
                let arguments: Seq<_> = self.parameters.iter().map(|f| f.value.name).collect();
                fn_body::parse_fn_body(
                    entity,
                    db,
                    &entity_macro_definitions,
                    &input,
                    &tokens,
                    self_argument,
                    arguments,
                )
            }
        }
    }
}