From fc70cea9b08afc13314012965791882709bed834 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Mon, 3 Jun 2024 22:07:39 -0500 Subject: [PATCH] analyzer: definition tracker --- src/analyzer.rs | 69 +++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index e384f9a..75696f7 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -1,5 +1,39 @@ use {super::*, CompileErrorKind::*}; +#[derive(Default)] +struct DefinitionTracker<'src> { + definitions: HashMap<&'src str, (&'static str, Name<'src>)>, +} + +impl<'src> DefinitionTracker<'src> { + fn define( + &mut self, + name: Name<'src>, + second_type: &'static str, + duplicates_allowed: bool, + ) -> CompileResult<'src> { + if let Some((first_type, original)) = self.definitions.get(name.lexeme()) { + if !(*first_type == second_type && duplicates_allowed) { + let (original, redefinition) = if name.line < original.line { + (name, *original) + } else { + (*original, name) + }; + + return Err(redefinition.token.error(Redefinition { + first_type, + second_type, + name: name.lexeme(), + first: original.line, + })); + } + } + + self.definitions.insert(name.lexeme(), (second_type, name)); + Ok(()) + } +} + #[derive(Default)] pub(crate) struct Analyzer<'src> { assignments: Table<'src, Assignment<'src>>, @@ -19,45 +53,18 @@ impl<'src> Analyzer<'src> { ) -> CompileResult<'src, Justfile<'src>> { let mut analyzer = Self::default(); + let mut definitions = DefinitionTracker::default(); let mut unprocessed_recipes = Vec::new(); let mut unprocessed_assignments = Vec::new(); let mut stack = Vec::new(); stack.push(asts.get(root).unwrap()); - let mut definitions: HashMap<&str, (&'static str, Name)> = HashMap::new(); - - let mut define = |name: Name<'src>, - second_type: &'static str, - duplicates_allowed: bool| - -> CompileResult<'src> { - if let Some((first_type, original)) = definitions.get(name.lexeme()) { - if !(*first_type == second_type && duplicates_allowed) { - let (original, redefinition) = if name.line < original.line { - (name, *original) - } else { - (*original, name) - }; - - return Err(redefinition.token.error(Redefinition { - first_type, - second_type, - name: name.lexeme(), - first: original.line, - })); - } - } - - definitions.insert(name.lexeme(), (second_type, name)); - - Ok(()) - }; - while let Some(ast) = stack.pop() { for item in &ast.items { match item { Item::Alias(alias) => { - define(alias.name, "alias", false)?; + definitions.define(alias.name, "alias", false)?; Self::analyze_alias(alias)?; analyzer.aliases.insert(alias.clone()); } @@ -72,7 +79,7 @@ impl<'src> Analyzer<'src> { } Item::Module { absolute, name, .. } => { if let Some(absolute) = absolute { - define(*name, "module", false)?; + definitions.define(*name, "module", false)?; analyzer .modules .insert(Self::analyze(loaded, paths, asts, absolute, Some(*name))?); @@ -119,7 +126,7 @@ impl<'src> Analyzer<'src> { let recipes = { let mut recipe_table: Table<'src, UnresolvedRecipe<'src>> = Table::default(); for recipe in unprocessed_recipes { - define(recipe.name, "recipe", settings.allow_duplicate_recipes)?; + definitions.define(recipe.name, "recipe", settings.allow_duplicate_recipes)?; if recipe_table .get(recipe.name.lexeme()) .map_or(true, |original| recipe.file_depth <= original.file_depth)