makefile_lossless/lib.rs
1#![allow(clippy::tabs_in_doc_comments)] // Makefile uses tabs
2#![deny(missing_docs)]
3
4//! A lossless parser for Makefiles
5//!
6//! Example:
7//!
8//! ```rust
9//! use std::io::Read;
10//! let contents = r#"PYTHON = python3
11//!
12//! .PHONY: all
13//!
14//! all: build
15//!
16//! build:
17//! $(PYTHON) setup.py build
18//! "#;
19//! let makefile: makefile_lossless::Makefile = contents.parse().unwrap();
20//!
21//! assert_eq!(makefile.rules().count(), 3);
22//! ```
23
24mod ast;
25mod incremental;
26mod lex;
27mod lossless;
28mod parse;
29mod pattern;
30mod text;
31
32pub use ast::makefile::MakefileItem;
33pub use ast::rule::RuleItem;
34pub use incremental::{apply_edit_to_text, TextEdit};
35pub use lossless::{
36 ArchiveMember, ArchiveMembers, Conditional, Error, ErrorInfo, Identifier, Include, Lang,
37 Makefile, ParseError, PositionedParseError, Recipe, Rule, VariableDefinition,
38 VariableReference,
39};
40pub use parse::Parse;
41pub use rowan::TextRange;
42pub use text::{is_in_prerequisites, variable_at_offset, word_at_offset};
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45/// The variant of makefile being parsed
46pub enum MakefileVariant {
47 /// GNU Make (most common, supports ifeq/ifneq/ifdef/ifndef conditionals, pattern rules, etc.)
48 GNUMake,
49 /// BSD Make (FreeBSD, NetBSD, OpenBSD - uses .if/.ifdef/.ifndef directives)
50 BSDMake,
51 /// Microsoft nmake (Windows - uses !IF/!IFDEF/!IFNDEF directives)
52 NMake,
53 /// POSIX-compliant make (basic portable subset, no extensions)
54 POSIXMake,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
58#[allow(non_camel_case_types)]
59#[repr(u16)]
60#[allow(missing_docs)]
61pub enum SyntaxKind {
62 IDENTIFIER = 0,
63 INDENT,
64 TEXT,
65 WHITESPACE,
66 NEWLINE,
67 DOLLAR,
68 LPAREN,
69 RPAREN,
70 LBRACE,
71 RBRACE,
72 QUOTE,
73 BACKSLASH,
74 COMMA,
75 OPERATOR,
76
77 COMMENT,
78 ERROR,
79
80 // composite nodes
81 ROOT, // The entire file
82 RULE, // A single rule
83 RECIPE, // A command/recipe line
84 VARIABLE, // A variable definition
85 EXPR, // An expression (e.g., targets before colon, or old-style prerequisites)
86 TARGETS, // Container for targets before the colon
87 PREREQUISITES, // Container for prerequisites after the colon
88 PREREQUISITE, // A single prerequisite item
89
90 // Directives
91 CONDITIONAL, // The entire conditional block (ifdef...endif)
92 CONDITIONAL_IF, // The initial conditional (ifdef/ifndef/ifeq/ifneq)
93 CONDITIONAL_ELSE, // An else or else-conditional clause
94 CONDITIONAL_ENDIF, // The endif keyword
95 INCLUDE,
96
97 // Archive members
98 ARCHIVE_MEMBERS, // Container for just the members inside parentheses
99 ARCHIVE_MEMBER, // Individual member like "bar.o" or "baz.o"
100
101 // Blank lines
102 BLANK_LINE, // A blank line between top-level items
103}
104
105/// Convert our `SyntaxKind` into the rowan `SyntaxKind`.
106impl From<SyntaxKind> for rowan::SyntaxKind {
107 fn from(kind: SyntaxKind) -> Self {
108 Self(kind as u16)
109 }
110}