resolve merge conflicts with master

This commit is contained in:
Connor Skees 2020-07-31 17:37:00 -04:00
commit 123ed80e9a
4 changed files with 148 additions and 25 deletions

View File

@ -26,6 +26,19 @@ impl Mixin {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Content { pub(crate) struct Content {
/// The literal block, serialized as a list of tokens
pub content: Option<Vec<Token>>, pub content: Option<Vec<Token>>,
/// Optional args, e.g. `@content(a, b, c);`
pub content_args: Option<FuncArgs>, pub content_args: Option<FuncArgs>,
/// The number of scopes at the use of `@include`
///
/// This is used to "reset" back to the state of the `@include`
/// without actually cloning the scope or putting it in an `Rc`
pub scope_len: usize,
/// Whether or not the mixin this `@content` block is inside of was
/// declared in the global scope
pub declared_at_root: bool,
} }

View File

@ -8,6 +8,7 @@ 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,
}; };
@ -129,6 +130,8 @@ impl<'a> Parser<'a> {
let scope = self.eval_args(fn_args, args)?; let scope = self.eval_args(fn_args, args)?;
let scope_len = self.scopes.len();
if declared_at_root { if declared_at_root {
mem::swap(self.scopes, self.content_scopes); mem::swap(self.scopes, self.content_scopes);
} }
@ -138,6 +141,8 @@ impl<'a> Parser<'a> {
self.content.push(Content { self.content.push(Content {
content, content,
content_args, content_args,
scope_len,
declared_at_root,
}); });
let body = Parser { let body = Parser {
@ -178,26 +183,35 @@ impl<'a> Parser<'a> {
.into()); .into());
} }
if let Some(Token { kind: '(', .. }) = self.toks.peek() { Ok(if let Some(content) = self.content.pop() {
self.toks.next(); let (mut scope_at_decl, mixin_scope) = if content.declared_at_root {
let args = self.parse_call_args()?; (mem::take(self.content_scopes), Scopes::new())
if let Some(Some(content_args)) = self.content.last().map(|v| v.content_args.clone()) {
args.max_args(content_args.len())?;
let scope = self.eval_args(content_args, args)?;
self.content_scopes.merge(scope);
} else { } else {
args.max_args(0)?; mem::take(self.scopes).split_off(content.scope_len)
} };
}
let mut entered_scope = false;
if let Some(Token { kind: '(', .. }) = self.toks.peek() {
self.toks.next();
let args = self.parse_call_args()?;
if let Some(ref content_args) = content.content_args {
args.max_args(content_args.len())?;
let scope = self.eval_args(content_args.clone(), args)?;
scope_at_decl.enter_scope(scope);
entered_scope = true;
} else {
args.max_args(0)?;
}
}
Ok(if let Some(content) = &self.content.pop() {
let stmts = if let Some(body) = content.content.clone() { let stmts = if let Some(body) = content.content.clone() {
Parser { 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: self.content_scopes, scopes: &mut scope_at_decl,
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,
@ -214,8 +228,21 @@ impl<'a> Parser<'a> {
} else { } else {
Vec::new() Vec::new()
}; };
self.content.push(content.clone());
self.scopes.exit_scope(); if entered_scope {
scope_at_decl.exit_scope();
}
scope_at_decl.merge(mixin_scope);
if content.declared_at_root {
*self.content_scopes = scope_at_decl;
} else {
*self.scopes = scope_at_decl;
}
self.content.push(content);
stmts stmts
} else { } else {
Vec::new() Vec::new()

View File

@ -93,6 +93,15 @@ impl Scopes {
Self(Vec::new()) Self(Vec::new())
} }
pub fn len(&self) -> usize {
self.0.len()
}
pub fn split_off(mut self, len: usize) -> (Scopes, Scopes) {
let split = self.0.split_off(len);
(self, Scopes(split))
}
pub fn enter_new_scope(&mut self) { pub fn enter_new_scope(&mut self) {
self.0.push(Scope::new()); self.0.push(Scope::new());
} }
@ -105,12 +114,8 @@ impl Scopes {
self.0.pop(); self.0.pop();
} }
pub fn merge(&mut self, other: Scope) { pub fn merge(&mut self, mut other: Self) {
if let Some(scope) = self.0.last_mut() { self.0.append(&mut other.0);
scope.merge(other)
} else {
panic!()
}
} }
} }

View File

@ -449,6 +449,84 @@ test!(
}", }",
"a {\n color: foo;\n color: foo;\n}\n" "a {\n color: foo;\n color: foo;\n}\n"
); );
test!(
can_access_variables_declared_before_content,
"@mixin foo {
$a: red;
@content;
color: $a;
}
a {
@include foo;
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_not_declared_at_root,
"a {
$a: red;
@mixin foo {
@content;
}
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_declared_at_root,
"@mixin foo {
@content;
}
a {
$a: red;
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_not_declared_at_root_and_modified,
"a {
$a: red;
@mixin foo {
$a: green;
@content;
}
@include foo {
color: $a;
}
}",
"a {\n color: green;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_declared_at_root_and_modified,
"@mixin foo {
$a: green;
@content;
}
a {
$a: red;
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
error!( error!(
mixin_in_function, mixin_in_function,
"@function foo() { "@function foo() {