avoid cloning the entire scope

This commit is contained in:
Connor Skees 2020-07-08 17:52:37 -04:00
parent 316316d3a0
commit 02efd09d80
12 changed files with 86 additions and 28 deletions

View File

@ -1,4 +1,4 @@
use crate::{args::FuncArgs, scope::Scopes, Token}; use crate::{args::FuncArgs, Token};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Mixin { pub(crate) struct Mixin {
@ -28,7 +28,6 @@ impl Mixin {
pub(crate) struct Content { pub(crate) struct Content {
pub content: Option<Vec<Token>>, pub content: Option<Vec<Token>>,
pub content_args: Option<FuncArgs>, pub content_args: Option<FuncArgs>,
pub scopes: Scopes,
} }
impl Content { impl Content {
@ -36,7 +35,6 @@ impl Content {
Self { Self {
content: None, content: None,
content_args: None, content_args: None,
scopes: Scopes::new(),
} }
} }
} }

View File

@ -157,6 +157,7 @@ pub fn from_path(p: &str) -> Result<String> {
at_root: true, at_root: true,
at_root_has_selector: false, at_root_has_selector: false,
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e))?; .map_err(|e| raw_to_parse_error(&map, *e))?;
@ -199,6 +200,7 @@ pub fn from_string(p: String) -> Result<String> {
at_root: true, at_root: true,
at_root_has_selector: false, at_root_has_selector: false,
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e))?; .map_err(|e| raw_to_parse_error(&map, *e))?;
@ -232,6 +234,7 @@ pub fn from_string(p: String) -> std::result::Result<String, JsValue> {
at_root: true, at_root: true,
at_root_has_selector: false, at_root_has_selector: false,
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?; .map_err(|e| raw_to_parse_error(&map, *e).to_string())?;

View File

@ -357,6 +357,10 @@ impl<'a> Parser<'a> {
mut args: CallArgs, mut args: CallArgs,
) -> SassResult<Scope> { ) -> SassResult<Scope> {
let mut scope = Scope::new(); let mut scope = Scope::new();
if fn_args.0.is_empty() {
args.max_args(0)?;
return Ok(scope);
}
self.scopes.enter_new_scope(); self.scopes.enter_new_scope();
for (idx, arg) in fn_args.0.iter_mut().enumerate() { for (idx, arg) in fn_args.0.iter_mut().enumerate() {
if arg.is_variadic { if arg.is_variadic {

View File

@ -51,6 +51,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_stmt()?; .parse_stmt()?;
} else { } else {
@ -108,6 +109,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_stmt()?; .parse_stmt()?;
} else { } else {
@ -134,6 +136,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_stmt(); .parse_stmt();
} }
@ -312,6 +315,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -332,6 +336,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?, .parse()?,
); );
@ -380,6 +385,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -400,6 +406,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?, .parse()?,
); );
@ -496,6 +503,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?; .parse()?;
if !these_stmts.is_empty() { if !these_stmts.is_empty() {
@ -516,6 +524,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?, .parse()?,
); );

View File

@ -106,6 +106,7 @@ impl<'a> Parser<'a> {
at_root: false, at_root: false,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?; .parse()?;

View File

@ -90,6 +90,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse(); .parse();
} }

View File

@ -164,6 +164,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
}) })
.parse_keyframes_selector()?; .parse_keyframes_selector()?;
@ -193,6 +194,7 @@ impl<'a> Parser<'a> {
at_root: false, at_root: false,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_stmt()?; .parse_stmt()?;

View File

@ -1,3 +1,5 @@
use std::mem;
use codemap::Spanned; use codemap::Spanned;
use peekmore::PeekMore; use peekmore::PeekMore;
@ -6,7 +8,6 @@ use crate::{
args::{CallArgs, FuncArgs}, args::{CallArgs, FuncArgs},
atrule::{Content, Mixin}, atrule::{Content, Mixin},
error::SassResult, error::SassResult,
scope::Scopes,
utils::read_until_closing_curly_brace, utils::read_until_closing_curly_brace,
Token, Token,
}; };
@ -121,30 +122,32 @@ impl<'a> Parser<'a> {
let scope = self.eval_args(fn_args, args)?; let scope = self.eval_args(fn_args, args)?;
let mut new_scope = Scopes::new(); let mut new_scope = std::mem::take(self.content_scopes);
let mut entered_scope = false;
if declared_at_root {
new_scope.enter_scope(scope);
} else {
entered_scope = true;
self.scopes.enter_scope(scope);
};
self.content.push(Content { self.content.push(Content {
content, content,
content_args, content_args,
scopes: self.scopes.clone(),
}); });
let mut scopes = if declared_at_root {
mem::take(&mut new_scope)
} else {
mem::take(self.scopes)
};
let mut content_scopes = if declared_at_root {
mem::take(self.scopes)
} else {
mem::take(&mut new_scope)
};
scopes.enter_scope(scope);
let body = Parser { let body = Parser {
toks: &mut body.into_iter().peekmore(), toks: &mut body.into_iter().peekmore(),
map: self.map, map: self.map,
path: self.path, path: self.path,
scopes: if declared_at_root { scopes: &mut scopes,
&mut new_scope
} else {
self.scopes
},
global_scope: self.global_scope, global_scope: self.global_scope,
super_selectors: self.super_selectors, super_selectors: self.super_selectors,
span_before: self.span_before, span_before: self.span_before,
@ -153,12 +156,18 @@ impl<'a> Parser<'a> {
at_root: false, at_root: false,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: &mut content_scopes,
} }
.parse()?; .parse()?;
self.content.pop(); self.content.pop();
if entered_scope { if declared_at_root {
self.scopes.exit_scope(); *self.scopes = content_scopes;
*self.content_scopes = scopes;
} else {
scopes.exit_scope();
*self.scopes = scopes;
*self.content_scopes = content_scopes;
} }
Ok(body) Ok(body)
@ -173,19 +182,14 @@ impl<'a> Parser<'a> {
.into()); .into());
} }
let mut scope = self
.content
.last()
.cloned()
.unwrap_or_else(Content::new)
.scopes;
if let Some(Token { kind: '(', .. }) = self.toks.peek() { if let Some(Token { kind: '(', .. }) = self.toks.peek() {
self.toks.next(); self.toks.next();
let args = self.parse_call_args()?; let args = self.parse_call_args()?;
if let Some(Some(content_args)) = self.content.last().map(|v| v.content_args.clone()) { if let Some(Some(content_args)) = self.content.last().map(|v| v.content_args.clone()) {
args.max_args(content_args.len())?; args.max_args(content_args.len())?;
scope.merge(self.eval_args(content_args, args)?); let scope = self.eval_args(content_args, args)?;
self.content_scopes.merge(scope);
} else { } else {
args.max_args(0)?; args.max_args(0)?;
} }
@ -197,7 +201,7 @@ impl<'a> Parser<'a> {
toks: &mut body.into_iter().peekmore(), toks: &mut body.into_iter().peekmore(),
map: self.map, map: self.map,
path: self.path, path: self.path,
scopes: &mut scope, scopes: self.content_scopes,
global_scope: self.global_scope, global_scope: self.global_scope,
super_selectors: self.super_selectors, super_selectors: self.super_selectors,
span_before: self.span_before, span_before: self.span_before,
@ -206,6 +210,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.scopes,
} }
.parse()? .parse()?
} else { } else {

View File

@ -70,6 +70,7 @@ pub(crate) struct Parser<'a> {
pub path: &'a Path, pub path: &'a Path,
pub global_scope: &'a mut Scope, pub global_scope: &'a mut Scope,
pub scopes: &'a mut Scopes, pub scopes: &'a mut Scopes,
pub content_scopes: &'a mut Scopes,
pub super_selectors: &'a mut NeverEmptyVec<Selector>, pub super_selectors: &'a mut NeverEmptyVec<Selector>,
pub span_before: Span, pub span_before: Span,
pub content: &'a mut Vec<Content>, pub content: &'a mut Vec<Content>,
@ -357,6 +358,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
}, },
allows_parent, allows_parent,
true, true,
@ -583,6 +585,7 @@ impl<'a> Parser<'a> {
at_root: false, at_root: false,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_stmt()?; .parse_stmt()?;
@ -649,6 +652,7 @@ impl<'a> Parser<'a> {
at_root: true, at_root: true,
at_root_has_selector, at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()? .parse()?
.into_iter() .into_iter()
@ -688,6 +692,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_selector(false, true, String::new())?; .parse_selector(false, true, String::new())?;
@ -764,6 +769,7 @@ impl<'a> Parser<'a> {
at_root: false, at_root: false,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse()?; .parse()?;

View File

@ -195,6 +195,7 @@ impl<'a> Parser<'a> {
at_root: self.at_root, at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector, at_root_has_selector: self.at_root_has_selector,
extender: self.extender, extender: self.extender,
content_scopes: self.content_scopes,
} }
.parse_value() .parse_value()
} }

View File

@ -444,6 +444,7 @@ impl Value {
at_root: parser.at_root, at_root: parser.at_root,
at_root_has_selector: parser.at_root_has_selector, at_root_has_selector: parser.at_root_has_selector,
extender: parser.extender, extender: parser.extender,
content_scopes: parser.content_scopes,
} }
.parse_selector(allows_parent, true, String::new()) .parse_selector(allows_parent, true, String::new())
} }

View File

@ -399,3 +399,30 @@ test!(
}", }",
"a {\n color: foo;\n color: bar;\n}\n" "a {\n color: foo;\n color: bar;\n}\n"
); );
test!(
three_depth_of_content,
"@mixin foo($arg) {
@include bar {
color: $arg;
}
}
@mixin bar {
@include baz {
@content;
}
}
@mixin baz {
@content;
}
@mixin font-size($value) {
@include foo($value);
}
a {
@include font-size(1rem);
}",
"a {\n color: 1rem;\n}\n"
);