respect $module argument to get-function

This commit is contained in:
Connor Skees 2020-07-30 17:46:56 -04:00
parent a03ad51b71
commit a7325436ca
8 changed files with 62 additions and 69 deletions

View File

@ -1,7 +1,5 @@
use super::{Builtin, GlobalFunctionMap, GLOBAL_FUNCTIONS}; use super::{Builtin, GlobalFunctionMap, GLOBAL_FUNCTIONS};
use codemap::Spanned;
use crate::{ use crate::{
args::CallArgs, args::CallArgs,
common::{Identifier, QuoteKind}, common::{Identifier, QuoteKind},
@ -166,7 +164,8 @@ pub(crate) fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR
} }
}; };
if module.is_some() && css { let func = match if let Some(module_name) = module {
if css {
return Err(( return Err((
"$css and $module may not both be passed at once.", "$css and $module may not both be passed at once.",
args.span(), args.span(),
@ -174,13 +173,13 @@ pub(crate) fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR
.into()); .into());
} }
let func = match parser.scopes.get_fn( parser
Spanned { .modules
node: name, .get(module_name.into(), args.span())?
span: args.span(), .get_fn(name)
}, } else {
parser.global_scope, parser.scopes.get_fn(name, parser.global_scope)
) { } {
Some(f) => f, Some(f) => f,
None => match GLOBAL_FUNCTIONS.get(name.as_str()) { None => match GLOBAL_FUNCTIONS.get(name.as_str()) {
Some(f) => SassFunction::Builtin(f.clone(), name), Some(f) => SassFunction::Builtin(f.clone(), name),

View File

@ -32,14 +32,7 @@ fn module_functions(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
}; };
Ok(Value::Map( Ok(Value::Map(
parser parser.modules.get(module.into(), args.span())?.functions(),
.modules
.get(&module)
.ok_or((
format!("There is no module with the namespace \"{}\".", module),
args.span(),
))?
.functions(),
)) ))
} }
@ -58,14 +51,7 @@ fn module_variables(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
}; };
Ok(Value::Map( Ok(Value::Map(
parser parser.modules.get(module.into(), args.span())?.variables(),
.modules
.get(&module)
.ok_or((
format!("There is no module with the namespace \"{}\".", module),
args.span(),
))?
.variables(),
)) ))
} }

View File

@ -2,7 +2,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use codemap::Spanned; use codemap::{Span, Spanned};
use crate::{ use crate::{
args::CallArgs, args::CallArgs,
@ -26,6 +26,29 @@ mod string;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct Module(pub Scope); pub(crate) struct Module(pub Scope);
#[derive(Debug, Default)]
pub(crate) struct Modules(BTreeMap<Identifier, Module>);
impl Modules {
pub fn insert(&mut self, name: Identifier, module: Module) {
self.0.insert(name, module);
}
pub fn get(&self, name: Identifier, span: Span) -> SassResult<&Module> {
match self.0.get(&name) {
Some(v) => Ok(v),
None => Err((
format!(
"There is no module with the namespace \"{}\".",
name.as_str()
),
span,
)
.into()),
}
}
}
impl Module { impl Module {
pub fn get_var(&self, name: Spanned<Identifier>) -> SassResult<&Value> { pub fn get_var(&self, name: Spanned<Identifier>) -> SassResult<&Value> {
match self.0.vars.get(&name.node) { match self.0.vars.get(&name.node) {

View File

@ -81,7 +81,7 @@ grass input.scss
)] )]
#![cfg_attr(feature = "nightly", feature(track_caller))] #![cfg_attr(feature = "nightly", feature(track_caller))]
#![cfg_attr(feature = "profiling", inline(never))] #![cfg_attr(feature = "profiling", inline(never))]
use std::{collections::HashMap, fs, path::Path}; use std::{fs, path::Path};
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@ -95,6 +95,7 @@ use peekmore::PeekMore;
pub use crate::error::{SassError as Error, SassResult as Result}; pub use crate::error::{SassError as Error, SassResult as Result};
pub(crate) use crate::token::Token; pub(crate) use crate::token::Token;
use crate::{ use crate::{
builtin::modules::Modules,
lexer::Lexer, lexer::Lexer,
output::Css, output::Css,
parse::{ parse::{
@ -293,7 +294,7 @@ pub fn from_path(p: &str, options: &Options) -> Result<String> {
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(), content_scopes: &mut Scopes::new(),
options, options,
modules: &mut HashMap::new(), modules: &mut Modules::default(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?; .map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
@ -338,7 +339,7 @@ pub fn from_string(p: String, options: &Options) -> Result<String> {
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(), content_scopes: &mut Scopes::new(),
options, options,
modules: &mut HashMap::new(), modules: &mut Modules::default(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?; .map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
@ -374,7 +375,7 @@ pub fn from_string(p: String) -> std::result::Result<String, JsValue> {
extender: &mut Extender::new(empty_span), extender: &mut Extender::new(empty_span),
content_scopes: &mut Scopes::new(), content_scopes: &mut Scopes::new(),
options: &Options::default(), options: &Options::default(),
modules: &mut HashMap::new(), modules: &mut Modules::default(),
} }
.parse() .parse()
.map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?; .map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?;

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, convert::TryFrom, fs, path::Path, vec::IntoIter}; use std::{convert::TryFrom, fs, path::Path, vec::IntoIter};
use codemap::{CodeMap, Span, Spanned}; use codemap::{CodeMap, Span, Spanned};
use peekmore::{PeekMore, PeekMoreIterator}; use peekmore::{PeekMore, PeekMoreIterator};
@ -11,7 +11,7 @@ use crate::{
}, },
builtin::modules::{ builtin::modules::{
declare_module_color, declare_module_list, declare_module_map, declare_module_math, declare_module_color, declare_module_list, declare_module_map, declare_module_math,
declare_module_meta, declare_module_selector, declare_module_string, Module, declare_module_meta, declare_module_selector, declare_module_string, Module, Modules,
}, },
error::SassResult, error::SassResult,
lexer::Lexer, lexer::Lexer,
@ -92,7 +92,7 @@ pub(crate) struct Parser<'a> {
pub options: &'a Options<'a>, pub options: &'a Options<'a>,
pub modules: &'a mut HashMap<String, Module>, pub modules: &'a mut Modules,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
@ -262,7 +262,7 @@ impl<'a> Parser<'a> {
}, },
}; };
self.modules.insert(module_name, module); self.modules.insert(module_name.into(), module);
} }
Some(Token { kind: '/', .. }) => { Some(Token { kind: '/', .. }) => {
self.toks.next(); self.toks.next();

View File

@ -261,14 +261,7 @@ impl<'a> Parser<'a> {
module_span = module_span.merge(var.span); module_span = module_span.merge(var.span);
let value = self let value = self.modules.get(module.into(), module_span)?.get_var(var)?;
.modules
.get(module)
.ok_or((
format!("There is no module with the namespace \"{}\".", module),
module_span,
))?
.get_var(var)?;
HigherIntermediateValue::Literal(value.clone()) HigherIntermediateValue::Literal(value.clone())
} else { } else {
let fn_name = self let fn_name = self
@ -277,11 +270,7 @@ impl<'a> Parser<'a> {
let function = self let function = self
.modules .modules
.get(module) .get(module.into(), module_span)?
.ok_or((
format!("There is no module with the namespace \"{}\".", module),
module_span,
))?
.get_fn(fn_name.node) .get_fn(fn_name.node)
.ok_or(("Undefined function.", fn_name.span))?; .ok_or(("Undefined function.", fn_name.span))?;
@ -341,13 +330,7 @@ impl<'a> Parser<'a> {
} }
let as_ident = Identifier::from(&s); let as_ident = Identifier::from(&s);
let func = match self.scopes.get_fn( let func = match self.scopes.get_fn(as_ident, self.global_scope) {
Spanned {
node: as_ident,
span,
},
self.global_scope,
) {
Some(f) => f, Some(f) => f,
None => { None => {
if let Some(f) = GLOBAL_FUNCTIONS.get(as_ident.as_str()) { if let Some(f) = GLOBAL_FUNCTIONS.get(as_ident.as_str()) {

View File

@ -230,17 +230,13 @@ impl Scopes {
} }
} }
pub fn get_fn<'a>( pub fn get_fn<'a>(&'a self, name: Identifier, global_scope: &'a Scope) -> Option<SassFunction> {
&'a self,
name: Spanned<Identifier>,
global_scope: &'a Scope,
) -> Option<SassFunction> {
for scope in self.0.iter().rev() { for scope in self.0.iter().rev() {
if scope.fn_exists(name.node) { if scope.fn_exists(name) {
return scope.get_fn(name.node); return scope.get_fn(name);
} }
} }
global_scope.get_fn(name.node) global_scope.get_fn(name)
} }
pub fn fn_exists(&self, name: Identifier, global_scope: &Scope) -> bool { pub fn fn_exists(&self, name: Identifier, global_scope: &Scope) -> bool {

View File

@ -121,3 +121,8 @@ test!(
"a {\n color: call(call(get-function(get-function), darken), red, 10%);\n}\n", "a {\n color: call(call(get-function(get-function), darken), red, 10%);\n}\n",
"a {\n color: #cc0000;\n}\n" "a {\n color: #cc0000;\n}\n"
); );
test!(
get_function_of_module,
"@use 'sass:math';\na {\n color: call(get-function(cos, $module: math), 2);\n}\n",
"a {\n color: -0.4161468365;\n}\n"
);