2020-08-19 07:13:32 -04:00
|
|
|
use codemap::Spanned;
|
|
|
|
|
|
|
|
use crate::{common::Identifier, error::SassResult, value::Value, Token};
|
2020-06-16 22:34:01 -04:00
|
|
|
|
2020-07-05 10:13:49 -04:00
|
|
|
use super::Parser;
|
2020-06-16 22:34:01 -04:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-08-07 02:01:04 -04:00
|
|
|
pub(crate) struct VariableValue {
|
2020-08-19 07:13:32 -04:00
|
|
|
pub var_value: SassResult<Spanned<Value>>,
|
2020-08-07 02:01:04 -04:00
|
|
|
pub global: bool,
|
|
|
|
pub default: bool,
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl VariableValue {
|
2020-08-19 07:13:32 -04:00
|
|
|
pub const fn new(var_value: SassResult<Spanned<Value>>, global: bool, default: bool) -> Self {
|
2020-06-16 22:34:01 -04:00
|
|
|
Self {
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value,
|
2020-06-16 22:34:01 -04:00
|
|
|
global,
|
|
|
|
default,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
pub(super) fn parse_variable_declaration(&mut self) -> SassResult<()> {
|
|
|
|
assert!(matches!(self.toks.next(), Some(Token { kind: '$', .. })));
|
|
|
|
let ident: Identifier = self.parse_identifier_no_interpolation(false)?.node.into();
|
2020-08-07 11:39:14 -04:00
|
|
|
self.whitespace_or_comment();
|
2020-08-06 21:36:11 -04:00
|
|
|
|
|
|
|
self.expect_char(':')?;
|
|
|
|
|
2020-07-24 20:12:50 -04:00
|
|
|
let VariableValue {
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value,
|
2020-07-24 20:12:50 -04:00
|
|
|
global,
|
|
|
|
default,
|
|
|
|
} = self.parse_variable_value()?;
|
2020-06-16 22:34:01 -04:00
|
|
|
|
2020-07-24 20:12:50 -04:00
|
|
|
if default {
|
2020-08-17 06:16:18 -04:00
|
|
|
let config_val = self.module_config.get(ident).filter(|v| !v.is_null());
|
2020-08-06 21:00:34 -04:00
|
|
|
|
2020-08-17 06:16:18 -04:00
|
|
|
let value = if (self.at_root && !self.flags.in_control_flow()) || global {
|
|
|
|
if self.global_scope.default_var_exists(ident) {
|
|
|
|
return Ok(());
|
|
|
|
} else if let Some(value) = config_val {
|
|
|
|
value
|
2020-08-06 21:00:34 -04:00
|
|
|
} else {
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value?.node
|
2020-08-17 06:16:18 -04:00
|
|
|
}
|
|
|
|
} else if self.at_root && self.flags.in_control_flow() {
|
|
|
|
if self.global_scope.default_var_exists(ident) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
2020-08-06 21:00:34 -04:00
|
|
|
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value?.node
|
2020-08-18 00:17:06 -04:00
|
|
|
} else if self.at_root {
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value?.node
|
2020-08-18 00:17:06 -04:00
|
|
|
} else {
|
2020-08-17 06:16:18 -04:00
|
|
|
if self.scopes.default_var_exists(ident) {
|
|
|
|
return Ok(());
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-08-17 06:16:18 -04:00
|
|
|
|
2020-08-19 07:13:32 -04:00
|
|
|
var_value?.node
|
2020-08-17 06:16:18 -04:00
|
|
|
};
|
|
|
|
|
2020-08-18 00:17:06 -04:00
|
|
|
if self.at_root && self.global_scope.var_exists(ident) {
|
|
|
|
if !self.global_scope.default_var_exists(ident) {
|
|
|
|
self.global_scope.insert_var(ident, value.clone());
|
|
|
|
}
|
|
|
|
} else if self.at_root
|
|
|
|
&& !self.flags.in_control_flow()
|
|
|
|
&& !self.global_scope.default_var_exists(ident)
|
|
|
|
{
|
|
|
|
self.global_scope.insert_var(ident, value.clone());
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-07-24 20:12:50 -04:00
|
|
|
|
2020-08-17 06:16:18 -04:00
|
|
|
if global {
|
|
|
|
self.global_scope.insert_var(ident, value.clone());
|
|
|
|
}
|
|
|
|
|
2020-08-18 00:17:06 -04:00
|
|
|
if self.at_root && !self.flags.in_control_flow() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2020-08-17 06:16:18 -04:00
|
|
|
self.scopes.insert_var(ident, value);
|
|
|
|
|
2020-07-24 20:12:50 -04:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2020-08-19 07:13:32 -04:00
|
|
|
let value = var_value?.node;
|
2020-07-24 20:12:50 -04:00
|
|
|
|
|
|
|
if global {
|
|
|
|
self.global_scope.insert_var(ident, value.clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.at_root {
|
2020-07-05 10:13:49 -04:00
|
|
|
if self.flags.in_control_flow() {
|
2020-07-08 22:38:56 -04:00
|
|
|
if self.global_scope.var_exists(ident) {
|
2020-07-24 20:12:50 -04:00
|
|
|
self.global_scope.insert_var(ident, value);
|
2020-06-16 22:34:01 -04:00
|
|
|
} else {
|
2020-07-24 20:12:50 -04:00
|
|
|
self.scopes.insert_var(ident, value);
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
} else {
|
2020-07-24 20:12:50 -04:00
|
|
|
self.global_scope.insert_var(ident, value);
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-08-18 05:55:54 -04:00
|
|
|
} else if !(self.flags.in_control_flow() && global) {
|
|
|
|
self.scopes.insert_var(ident, value);
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-08-07 02:01:04 -04:00
|
|
|
pub(super) fn parse_variable_value(&mut self) -> SassResult<VariableValue> {
|
2020-06-16 22:34:01 -04:00
|
|
|
let mut default = false;
|
|
|
|
let mut global = false;
|
|
|
|
|
2020-08-19 07:13:32 -04:00
|
|
|
let value = self.parse_value(true, &|toks| {
|
|
|
|
if matches!(toks.peek(), Some(Token { kind: '!', .. })) {
|
|
|
|
let is_important = matches!(toks.peek_next(), Some(Token { kind: 'i', .. }) | Some(Token { kind: 'I', .. }) | Some(Token { kind: '=', .. }));
|
|
|
|
toks.reset_cursor();
|
|
|
|
!is_important
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// todo: it should not be possible to declare the same flag more than once
|
|
|
|
while self.consume_char_if_exists('!') {
|
|
|
|
let flag = self.parse_identifier_no_interpolation(false)?;
|
|
|
|
|
|
|
|
match flag.node.as_str() {
|
|
|
|
"global" => {
|
|
|
|
self.toks.truncate_iterator_to_cursor();
|
|
|
|
global = true;
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-08-19 07:13:32 -04:00
|
|
|
"default" => {
|
|
|
|
self.toks.truncate_iterator_to_cursor();
|
|
|
|
default = true;
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-08-19 07:13:32 -04:00
|
|
|
_ => {
|
|
|
|
return Err(("Invalid flag name.", flag.span).into());
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
2020-08-19 07:13:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
self.whitespace_or_comment();
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.toks.peek() {
|
|
|
|
Some(Token { kind: ';', .. }) => {
|
|
|
|
self.toks.next();
|
|
|
|
}
|
|
|
|
Some(Token { kind: '}', .. }) => {}
|
|
|
|
Some(..) | None => {
|
|
|
|
value?;
|
|
|
|
self.expect_char(';')?;
|
|
|
|
unreachable!()
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
}
|
2020-07-24 20:12:50 -04:00
|
|
|
|
2020-08-19 07:13:32 -04:00
|
|
|
Ok(VariableValue::new(value, global, default))
|
2020-06-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
}
|