erl_parse 0.0.8

Erlang source code parser
Documentation
use erl_tokenize::tokens::AtomToken;
use erl_tokenize::values::Symbol;
use erl_tokenize::{LexicalToken, Position, PositionRange};

use super::forms;
use crate::traits::{Parse, TokenRead};
use crate::{ErrorKind, Parser, Result};

#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Form {
    ModuleAttr(forms::ModuleAttr),
    ExportAttr(forms::ExportAttr),
    ExportTypeAttr(forms::ExportTypeAttr),
    ImportAttr(forms::ImportAttr),
    FileAttr(forms::FileAttr),
    WildAttr(forms::WildAttr),
    FunSpec(forms::FunSpec),
    CallbackSpec(forms::CallbackSpec),
    FunDecl(forms::FunDecl),
    RecordDecl(forms::RecordDecl),
    TypeDecl(forms::TypeDecl),
}
impl Parse for Form {
    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
    where
        T: TokenRead,
    {
        let kind = track!(FormKind::guess(parser))?;
        Ok(match kind {
            FormKind::ModuleAttr => Form::ModuleAttr(track!(parser.parse())?),
            FormKind::ExportAttr => Form::ExportAttr(track!(parser.parse())?),
            FormKind::ExportTypeAttr => Form::ExportTypeAttr(track!(parser.parse())?),
            FormKind::ImportAttr => Form::ImportAttr(track!(parser.parse())?),
            FormKind::FileAttr => Form::FileAttr(track!(parser.parse())?),
            FormKind::WildAttr => Form::WildAttr(track!(parser.parse())?),
            FormKind::FunSpec => Form::FunSpec(track!(parser.parse())?),
            FormKind::CallbackSpec => Form::CallbackSpec(track!(parser.parse())?),
            FormKind::FunDecl => Form::FunDecl(track!(parser.parse())?),
            FormKind::RecordDecl => Form::RecordDecl(track!(parser.parse())?),
            FormKind::TypeDecl => Form::TypeDecl(track!(parser.parse())?),
        })
    }
}
impl PositionRange for Form {
    fn start_position(&self) -> Position {
        match *self {
            Form::ModuleAttr(ref t) => t.start_position(),
            Form::ExportAttr(ref t) => t.start_position(),
            Form::ExportTypeAttr(ref t) => t.start_position(),
            Form::ImportAttr(ref t) => t.start_position(),
            Form::FileAttr(ref t) => t.start_position(),
            Form::WildAttr(ref t) => t.start_position(),
            Form::FunSpec(ref t) => t.start_position(),
            Form::CallbackSpec(ref t) => t.start_position(),
            Form::FunDecl(ref t) => t.start_position(),
            Form::RecordDecl(ref t) => t.start_position(),
            Form::TypeDecl(ref t) => t.start_position(),
        }
    }
    fn end_position(&self) -> Position {
        match *self {
            Form::ModuleAttr(ref t) => t.end_position(),
            Form::ExportAttr(ref t) => t.end_position(),
            Form::ExportTypeAttr(ref t) => t.end_position(),
            Form::ImportAttr(ref t) => t.end_position(),
            Form::FileAttr(ref t) => t.end_position(),
            Form::WildAttr(ref t) => t.end_position(),
            Form::FunSpec(ref t) => t.end_position(),
            Form::CallbackSpec(ref t) => t.end_position(),
            Form::FunDecl(ref t) => t.end_position(),
            Form::RecordDecl(ref t) => t.end_position(),
            Form::TypeDecl(ref t) => t.end_position(),
        }
    }
}

#[derive(Debug)]
pub enum FormKind {
    ModuleAttr,
    ExportAttr,
    ExportTypeAttr,
    ImportAttr,
    FileAttr,
    WildAttr,
    FunSpec,
    CallbackSpec,
    FunDecl,
    RecordDecl,
    TypeDecl,
}
impl FormKind {
    pub fn guess<T>(parser: &mut Parser<T>) -> Result<Self>
    where
        T: TokenRead,
    {
        parser.peek(|parser| {
            Ok(match track!(parser.parse())? {
                LexicalToken::Symbol(ref t) if t.value() == Symbol::Hyphen => {
                    match track!(parser.parse::<AtomToken>())?.value() {
                        "module" => FormKind::ModuleAttr,
                        "export" => FormKind::ExportAttr,
                        "export_type" => FormKind::ExportTypeAttr,
                        "import" => FormKind::ImportAttr,
                        "file" => FormKind::FileAttr,
                        "spec" => FormKind::FunSpec,
                        "callback" => FormKind::CallbackSpec,
                        "record" => FormKind::RecordDecl,
                        "type" | "opaque" => FormKind::TypeDecl,
                        _ => FormKind::WildAttr,
                    }
                }
                LexicalToken::Atom(_) => FormKind::FunDecl,
                token => track_panic!(ErrorKind::UnexpectedToken(token)),
            })
        })
    }
}