aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-06-29 20:24:03 -0600
committerMelody Horn <melody@boringcactus.com>2021-06-29 20:24:03 -0600
commit756fd8977577d98ecc20babd7dad61324e6b4ecd (patch)
treea98b925b91acadeb2f7bde818985225b72e47a01 /src
parent2e576c9c0c95dbd5676fb684bd50b1876f738d64 (diff)
downloadriir-wxwidgets-756fd8977577d98ecc20babd7dad61324e6b4ecd.tar.gz
riir-wxwidgets-756fd8977577d98ecc20babd7dad61324e6b4ecd.zip
parse the easy one
Diffstat (limited to 'src')
-rw-r--r--src/parse.rs122
1 files changed, 119 insertions, 3 deletions
diff --git a/src/parse.rs b/src/parse.rs
index e528f01..b16fc24 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -1,6 +1,122 @@
+enum Context<'a> {
+ HalfIncludeGuard(&'a str),
+ IncludeGuard(&'a str),
+ If(&'a str),
+ Ifndef(&'a str),
+}
+
+impl<'a> Context<'a> {
+ fn modality(&self) -> Option<Modality<'a>> {
+ match self {
+ Context::HalfIncludeGuard(_) => None,
+ Context::IncludeGuard(_) => None,
+ Context::If(x) => Some(Modality::If(x)),
+ Context::Ifndef(x) => Some(Modality::Ifndef(x)),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum Modality<'a> {
+ If(&'a str),
+ Ifndef(&'a str),
+
+ And(Vec<Self>),
+}
+
+impl<'a> Modality<'a> {
+ fn and(a: Option<Self>, b: Option<Self>) -> Option<Self> {
+ match (a, b) {
+ (Some(a), Some(b)) => Some(Self::And(vec![a, b])),
+ (Some(a), None) => Some(a),
+ (None, Some(b)) => Some(b),
+ (None, None) => None,
+ }
+ }
+}
+
+trait VecContextExt<'a> {
+ fn modality(&self) -> Option<Modality<'a>>;
+}
+
+impl<'a> VecContextExt<'a> for Vec<Context<'a>> {
+ fn modality(&self) -> Option<Modality<'a>> {
+ self.iter()
+ .rev()
+ .map(Context::modality)
+ .fold(None, Modality::and)
+ }
+}
+
#[derive(Debug)]
-pub struct FileItem;
+enum FileItem<'a> {
+ LineComment(&'a str),
+ IncludeLocal(&'a str),
+ IncludeGlobal(&'a str),
+}
+
+#[derive(Debug)]
+pub struct FullFileItem<'a> {
+ data: FileItem<'a>,
+ modality: Option<Modality<'a>>,
+}
-pub fn parse(file: &str) -> Vec<FileItem> {
- todo!()
+pub fn parse(file: &str) -> Vec<FullFileItem> {
+ let mut context: Vec<Context> = vec![];
+ let mut result = vec![];
+ for line in file.lines() {
+ if line.starts_with("//") {
+ result.push(FullFileItem {
+ data: FileItem::LineComment(line.strip_prefix("//").unwrap()),
+ modality: context.modality(),
+ });
+ } else if line.trim().is_empty() {
+ // don't do anything
+ } else if line.starts_with("#ifndef ") && context.is_empty() {
+ // this is probably the include guard
+ context.push(Context::HalfIncludeGuard(
+ line.strip_prefix("#ifndef ").unwrap(),
+ ));
+ } else if line.starts_with("#define ") {
+ match context.last() {
+ Some(Context::HalfIncludeGuard(expected_guard)) => {
+ // this is the other half of the include guard
+ let actual_guard = line.strip_prefix("#define ").unwrap();
+ assert_eq!(
+ actual_guard, *expected_guard,
+ "weird other half of include guard"
+ );
+ context.pop();
+ context.push(Context::IncludeGuard(actual_guard));
+ }
+ _ => {
+ todo!("handle #define in non-include guard contexts: {:?}", line);
+ }
+ }
+ } else if line.trim().starts_with("#include ") {
+ let good_part = line.trim().strip_prefix("#include ").unwrap();
+ let item = if line.ends_with("\"") {
+ FileItem::IncludeLocal(good_part.trim_matches('"'))
+ } else if line.ends_with(">") {
+ FileItem::IncludeGlobal(good_part.trim_start_matches('<').trim_end_matches('>'))
+ } else {
+ todo!("handle weird includes {:?}", line);
+ };
+ result.push(FullFileItem {
+ data: item,
+ modality: context.modality(),
+ });
+ } else if line.starts_with("#if ") {
+ let condition = line.strip_prefix("#if ").unwrap();
+ context.push(Context::If(condition));
+ } else if line.starts_with("#ifndef ") {
+ let condition = line.strip_prefix("#ifndef ").unwrap();
+ context.push(Context::Ifndef(condition));
+ } else if line.starts_with("#endif") {
+ context.pop();
+ } else {
+ todo!("handle line {:?}", line);
+ }
+ }
+ result
}