analyzer: definition tracker
This commit is contained in:
parent
ed2c5c45e5
commit
fc70cea9b0
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user