derive: MapChain does not need to be generic

This commit is contained in:
René Kijewski 2024-11-23 21:03:21 +01:00
parent 07e6216e83
commit 466b92559a

View File

@ -3,7 +3,7 @@ use std::collections::hash_map::{Entry, HashMap};
use std::ops::Deref; use std::ops::Deref;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::{cmp, hash, mem, str}; use std::{mem, str};
use parser::node::{ use parser::node::{
Call, Comment, Cond, CondTest, FilterBlock, If, Include, Let, Lit, Loop, Macro, Match, Call, Comment, Cond, CondTest, FilterBlock, If, Include, Let, Lit, Loop, Macro, Match,
@ -65,7 +65,7 @@ struct Generator<'a> {
// The heritage contains references to blocks and their ancestry // The heritage contains references to blocks and their ancestry
heritage: Option<&'a Heritage<'a>>, heritage: Option<&'a Heritage<'a>>,
// Variables accessible directly from the current scope (not redirected to context) // Variables accessible directly from the current scope (not redirected to context)
locals: MapChain<'a, Cow<'a, str>, LocalMeta>, locals: MapChain<'a>,
// Suffix whitespace from the previous literal. Will be flushed to the // Suffix whitespace from the previous literal. Will be flushed to the
// output buffer unless suppressed by whitespace suppression on the next // output buffer unless suppressed by whitespace suppression on the next
// non-literal. // non-literal.
@ -86,7 +86,7 @@ impl<'a> Generator<'a> {
input: &'n TemplateInput<'_>, input: &'n TemplateInput<'_>,
contexts: &'n HashMap<&'n Arc<Path>, Context<'n>, FxBuildHasher>, contexts: &'n HashMap<&'n Arc<Path>, Context<'n>, FxBuildHasher>,
heritage: Option<&'n Heritage<'_>>, heritage: Option<&'n Heritage<'_>>,
locals: MapChain<'n, Cow<'n, str>, LocalMeta>, locals: MapChain<'n>,
buf_writable_discard: bool, buf_writable_discard: bool,
is_in_filter_block: usize, is_in_filter_block: usize,
) -> Generator<'n> { ) -> Generator<'n> {
@ -304,8 +304,7 @@ impl<'a> Generator<'a> {
} }
fn is_var_defined(&self, var_name: &str) -> bool { fn is_var_defined(&self, var_name: &str) -> bool {
self.locals.get(&var_name.into()).is_some() self.locals.get(var_name).is_some() || self.input.fields.iter().any(|f| f == var_name)
|| self.input.fields.iter().any(|f| f == var_name)
} }
fn evaluate_condition( fn evaluate_condition(
@ -991,7 +990,7 @@ impl<'a> Generator<'a> {
match var { match var {
Target::Name(name) => { Target::Name(name) => {
let name = normalize_identifier(name); let name = normalize_identifier(name);
match self.locals.get(&Cow::Borrowed(name)) { match self.locals.get(name) {
// declares a new variable // declares a new variable
None => Ok(false), None => Ok(false),
// an initialized variable gets shadowed // an initialized variable gets shadowed
@ -1062,7 +1061,7 @@ impl<'a> Generator<'a> {
} }
if shadowed if shadowed
|| !matches!(l.var, Target::Name(_)) || !matches!(l.var, Target::Name(_))
|| matches!(&l.var, Target::Name(name) if self.locals.get(&Cow::Borrowed(name)).is_none()) || matches!(&l.var, Target::Name(name) if self.locals.get(name).is_none())
{ {
buf.write("let "); buf.write("let ");
} }
@ -1165,10 +1164,7 @@ impl<'a> Generator<'a> {
// `<'b, 'b, ...>`. Except... it doesn't work because `self` still doesn't live long // `<'b, 'b, ...>`. Except... it doesn't work because `self` still doesn't live long
// enough here for some reason... // enough here for some reason...
MapChain::with_parent(unsafe { MapChain::with_parent(unsafe {
mem::transmute::< mem::transmute::<&MapChain<'_>, &MapChain<'_>>(&self.locals)
&MapChain<'_, Cow<'_, str>, LocalMeta>,
&MapChain<'_, Cow<'_, str>, LocalMeta>,
>(&self.locals)
}), }),
self.buf_writable.discard, self.buf_writable.discard,
self.is_in_filter_block, self.is_in_filter_block,
@ -2766,20 +2762,13 @@ impl LocalMeta {
} }
} }
#[derive(Debug, Clone)] struct MapChain<'a> {
struct MapChain<'a, K, V> parent: Option<&'a MapChain<'a>>,
where scopes: Vec<HashMap<Cow<'a, str>, LocalMeta, FxBuildHasher>>,
K: cmp::Eq + hash::Hash,
{
parent: Option<&'a MapChain<'a, K, V>>,
scopes: Vec<HashMap<K, V, FxBuildHasher>>,
} }
impl<'a, K: 'a, V: 'a> MapChain<'a, K, V> impl<'a> MapChain<'a> {
where fn with_parent(parent: &'a MapChain<'_>) -> MapChain<'a> {
K: cmp::Eq + hash::Hash,
{
fn with_parent<'p>(parent: &'p MapChain<'_, K, V>) -> MapChain<'p, K, V> {
MapChain { MapChain {
parent: Some(parent), parent: Some(parent),
scopes: vec![HashMap::default()], scopes: vec![HashMap::default()],
@ -2788,7 +2777,7 @@ where
/// Iterates the scopes in reverse and returns `Some(LocalMeta)` /// Iterates the scopes in reverse and returns `Some(LocalMeta)`
/// from the first scope where `key` exists. /// from the first scope where `key` exists.
fn get(&self, key: &K) -> Option<&V> { fn get<'b>(&'b self, key: &str) -> Option<&'b LocalMeta> {
let mut scopes = self.scopes.iter().rev(); let mut scopes = self.scopes.iter().rev();
scopes scopes
.find_map(|set| set.get(key)) .find_map(|set| set.get(key))
@ -2799,7 +2788,7 @@ where
self.scopes.last().unwrap().is_empty() self.scopes.last().unwrap().is_empty()
} }
fn insert(&mut self, key: K, val: V) { fn insert(&mut self, key: Cow<'a, str>, val: LocalMeta) {
self.scopes.last_mut().unwrap().insert(key, val); self.scopes.last_mut().unwrap().insert(key, val);
// Note that if `insert` returns `Some` then it implies // Note that if `insert` returns `Some` then it implies
@ -2809,15 +2798,10 @@ where
// compile error "identifier `a` used more than once". // compile error "identifier `a` used more than once".
} }
fn insert_with_default(&mut self, key: K) fn insert_with_default(&mut self, key: Cow<'a, str>) {
where self.insert(key, LocalMeta::default());
V: Default,
{
self.insert(key, V::default());
} }
}
impl MapChain<'_, Cow<'_, str>, LocalMeta> {
fn resolve(&self, name: &str) -> Option<String> { fn resolve(&self, name: &str) -> Option<String> {
let name = normalize_identifier(name); let name = normalize_identifier(name);
self.get(&Cow::Borrowed(name)).map(|meta| match &meta.refs { self.get(&Cow::Borrowed(name)).map(|meta| match &meta.refs {
@ -2832,7 +2816,7 @@ impl MapChain<'_, Cow<'_, str>, LocalMeta> {
} }
} }
impl<'a, K: Eq + hash::Hash, V> Default for MapChain<'a, K, V> { impl Default for MapChain<'_> {
fn default() -> Self { fn default() -> Self {
Self { Self {
parent: None, parent: None,