gomod_rs/
lib.rs

1use std::ops::Deref;
2
3use nom::{error::Error, Err};
4use nom_locate::LocatedSpan;
5
6mod parser;
7
8type Span<'a> = LocatedSpan<&'a str>;
9
10#[derive(Debug)]
11pub enum Sundry<'a> {
12    Comment(Span<'a>),
13    Empty(Span<'a>),
14    EOF,
15}
16
17#[derive(Debug, PartialEq, Eq)]
18pub enum Identifier<'a> {
19    Raw(&'a str),
20    Interpreted(String),
21}
22
23impl Deref for Identifier<'_> {
24    type Target = str;
25
26    fn deref(&self) -> &Self::Target {
27        match self {
28            Self::Raw(s) => s,
29            Self::Interpreted(s) => s.as_str(),
30        }
31    }
32}
33
34#[derive(Debug, PartialEq, Eq)]
35pub enum RetractSpec<'a> {
36    Version(Identifier<'a>),
37    Range((Identifier<'a>, Identifier<'a>)),
38}
39
40#[derive(Debug, PartialEq, Eq)]
41pub struct ReplaceSpec<'a> {
42    pub module_path: &'a str,
43    pub version: Option<Identifier<'a>>,
44    pub replacement: Replacement<'a>,
45}
46
47#[derive(Debug, PartialEq, Eq)]
48pub enum Replacement<'a> {
49    FilePath(Identifier<'a>),
50    Module((&'a str, Identifier<'a>)),
51}
52
53// comments on directive includes preceding-line comments and same-line comment
54#[derive(Debug, PartialEq, Eq)]
55pub enum Directive<'a> {
56    Module {
57        module_path: &'a str,
58    },
59    Go {
60        version: Identifier<'a>,
61    },
62    Require {
63        specs: Vec<Context<'a, (&'a str, Identifier<'a>)>>,
64    },
65    Toolchain {
66        name: Identifier<'a>,
67    },
68    Godebug {
69        specs: Vec<Context<'a, (&'a str, &'a str)>>,
70    },
71    Replace {
72        specs: Vec<Context<'a, ReplaceSpec<'a>>>,
73    },
74    Exclude {
75        specs: Vec<Context<'a, (&'a str, Identifier<'a>)>>,
76    },
77    Retract {
78        specs: Vec<Context<'a, RetractSpec<'a>>>,
79    },
80}
81
82#[derive(Debug, Default, PartialEq, Eq)]
83pub struct Location {
84    pub line: u32,
85    pub offset: usize,
86}
87
88pub type Range = (Location, Location);
89
90#[derive(Debug, PartialEq, Eq)]
91pub struct Context<'a, T: 'a> {
92    pub range: Range,
93    pub comments: Vec<&'a str>,
94    pub value: T,
95}
96
97pub type GoMod<'a> = Vec<Context<'a, Directive<'a>>>;
98
99/// Return an error indicating (line, offset)
100pub fn parse_gomod(text: &str) -> Result<GoMod, Err<Error<(u32, usize)>>> {
101    let (_, ret) = parser::parse_gomod(Span::new(text))
102        .map_err(|e| e.map_input(|i| (i.location_line(), i.location_offset())))?;
103    Ok(ret)
104}