oak_dockerfile/parser/
mod.rs1pub mod element_type;
3
4use crate::{language::DockerfileLanguage, lexer::DockerfileLexer, parser::element_type::DockerfileElementType};
5use oak_core::{
6 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
7 source::{Source, TextEdit},
8};
9
10pub struct DockerfileParser<'config> {
12 pub(crate) config: &'config DockerfileLanguage,
13}
14
15impl<'config> DockerfileParser<'config> {
16 pub fn new(config: &'config DockerfileLanguage) -> Self {
18 Self { config }
19 }
20}
21
22impl<'config> Parser<DockerfileLanguage> for DockerfileParser<'config> {
23 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<DockerfileLanguage>) -> ParseOutput<'a, DockerfileLanguage> {
24 let lexer = DockerfileLexer::new(&self.config);
25 parse_with_lexer(&lexer, text, edits, cache, |state| {
26 let root_checkpoint = state.checkpoint();
27 while state.not_at_end() {
28 if state.at(crate::lexer::token_type::DockerfileTokenType::Whitespace) || state.at(crate::lexer::token_type::DockerfileTokenType::Newline) {
29 state.advance();
30 continue;
31 }
32
33 if state.at(crate::lexer::token_type::DockerfileTokenType::Comment) {
34 let checkpoint = state.checkpoint();
35 state.advance();
36 state.finish_at(checkpoint, DockerfileElementType::Comment);
37 continue;
38 }
39
40 let instruction_checkpoint = state.checkpoint();
42 let kind = match state.peek_kind() {
43 Some(crate::lexer::token_type::DockerfileTokenType::From) => Some(DockerfileElementType::From),
44 Some(crate::lexer::token_type::DockerfileTokenType::Run) => Some(DockerfileElementType::Run),
45 Some(crate::lexer::token_type::DockerfileTokenType::Cmd) => Some(DockerfileElementType::Cmd),
46 Some(crate::lexer::token_type::DockerfileTokenType::Label) => Some(DockerfileElementType::Label),
47 Some(crate::lexer::token_type::DockerfileTokenType::Expose) => Some(DockerfileElementType::Expose),
48 Some(crate::lexer::token_type::DockerfileTokenType::Env) => Some(DockerfileElementType::Env),
49 Some(crate::lexer::token_type::DockerfileTokenType::Add) => Some(DockerfileElementType::Add),
50 Some(crate::lexer::token_type::DockerfileTokenType::Copy) => Some(DockerfileElementType::Copy),
51 Some(crate::lexer::token_type::DockerfileTokenType::Entrypoint) => Some(DockerfileElementType::Entrypoint),
52 Some(crate::lexer::token_type::DockerfileTokenType::Volume) => Some(DockerfileElementType::Volume),
53 Some(crate::lexer::token_type::DockerfileTokenType::User) => Some(DockerfileElementType::User),
54 Some(crate::lexer::token_type::DockerfileTokenType::Workdir) => Some(DockerfileElementType::Workdir),
55 Some(crate::lexer::token_type::DockerfileTokenType::Arg) => Some(DockerfileElementType::Arg),
56 Some(crate::lexer::token_type::DockerfileTokenType::Onbuild) => Some(DockerfileElementType::Onbuild),
57 Some(crate::lexer::token_type::DockerfileTokenType::Stopsignal) => Some(DockerfileElementType::Stopsignal),
58 Some(crate::lexer::token_type::DockerfileTokenType::Healthcheck) => Some(DockerfileElementType::Healthcheck),
59 Some(crate::lexer::token_type::DockerfileTokenType::Shell) => Some(DockerfileElementType::Shell),
60 Some(crate::lexer::token_type::DockerfileTokenType::Maintainer) => Some(DockerfileElementType::Maintainer),
61 _ => None,
62 };
63
64 if let Some(kind) = kind {
65 state.advance(); while state.not_at_end() && !state.at(crate::lexer::token_type::DockerfileTokenType::Newline) {
68 state.advance();
69 }
70 state.finish_at(instruction_checkpoint, kind);
71 }
72 else {
73 state.advance();
75 }
76 }
77 Ok(state.finish_at(root_checkpoint, DockerfileElementType::Root))
78 })
79 }
80}