From a7325436ca56851d7e613f402166ad2879192b25 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Thu, 30 Jul 2020 17:46:56 -0400 Subject: [PATCH] respect `$module` argument to `get-function` --- src/builtin/functions/meta.rs | 31 +++++++++++++++---------------- src/builtin/modules/meta.rs | 18 ++---------------- src/builtin/modules/mod.rs | 25 ++++++++++++++++++++++++- src/lib.rs | 9 +++++---- src/parse/mod.rs | 8 ++++---- src/parse/value/parse.rs | 23 +++-------------------- src/scope.rs | 12 ++++-------- tests/get-function.rs | 5 +++++ 8 files changed, 62 insertions(+), 69 deletions(-) diff --git a/src/builtin/functions/meta.rs b/src/builtin/functions/meta.rs index a5e0087..858f829 100644 --- a/src/builtin/functions/meta.rs +++ b/src/builtin/functions/meta.rs @@ -1,7 +1,5 @@ use super::{Builtin, GlobalFunctionMap, GLOBAL_FUNCTIONS}; -use codemap::Spanned; - use crate::{ args::CallArgs, common::{Identifier, QuoteKind}, @@ -166,21 +164,22 @@ pub(crate) fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR } }; - if module.is_some() && css { - return Err(( - "$css and $module may not both be passed at once.", - args.span(), - ) - .into()); - } + let func = match if let Some(module_name) = module { + if css { + return Err(( + "$css and $module may not both be passed at once.", + args.span(), + ) + .into()); + } - let func = match parser.scopes.get_fn( - Spanned { - node: name, - span: args.span(), - }, - parser.global_scope, - ) { + parser + .modules + .get(module_name.into(), args.span())? + .get_fn(name) + } else { + parser.scopes.get_fn(name, parser.global_scope) + } { Some(f) => f, None => match GLOBAL_FUNCTIONS.get(name.as_str()) { Some(f) => SassFunction::Builtin(f.clone(), name), diff --git a/src/builtin/modules/meta.rs b/src/builtin/modules/meta.rs index de6153a..1e0062e 100644 --- a/src/builtin/modules/meta.rs +++ b/src/builtin/modules/meta.rs @@ -32,14 +32,7 @@ fn module_functions(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult) -> SassResult); + +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 { pub fn get_var(&self, name: Spanned) -> SassResult<&Value> { match self.0.vars.get(&name.node) { diff --git a/src/lib.rs b/src/lib.rs index dbea119..4e8cc6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ grass input.scss )] #![cfg_attr(feature = "nightly", feature(track_caller))] #![cfg_attr(feature = "profiling", inline(never))] -use std::{collections::HashMap, fs, path::Path}; +use std::{fs, path::Path}; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -95,6 +95,7 @@ use peekmore::PeekMore; pub use crate::error::{SassError as Error, SassResult as Result}; pub(crate) use crate::token::Token; use crate::{ + builtin::modules::Modules, lexer::Lexer, output::Css, parse::{ @@ -293,7 +294,7 @@ pub fn from_path(p: &str, options: &Options) -> Result { extender: &mut Extender::new(empty_span), content_scopes: &mut Scopes::new(), options, - modules: &mut HashMap::new(), + modules: &mut Modules::default(), } .parse() .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 { extender: &mut Extender::new(empty_span), content_scopes: &mut Scopes::new(), options, - modules: &mut HashMap::new(), + modules: &mut Modules::default(), } .parse() .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 { extender: &mut Extender::new(empty_span), content_scopes: &mut Scopes::new(), options: &Options::default(), - modules: &mut HashMap::new(), + modules: &mut Modules::default(), } .parse() .map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?; diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 4f189ac..074f778 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -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 peekmore::{PeekMore, PeekMoreIterator}; @@ -11,7 +11,7 @@ use crate::{ }, builtin::modules::{ 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, lexer::Lexer, @@ -92,7 +92,7 @@ pub(crate) struct Parser<'a> { pub options: &'a Options<'a>, - pub modules: &'a mut HashMap, + pub modules: &'a mut Modules, } 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: '/', .. }) => { self.toks.next(); diff --git a/src/parse/value/parse.rs b/src/parse/value/parse.rs index fcbbdfd..0e268e2 100644 --- a/src/parse/value/parse.rs +++ b/src/parse/value/parse.rs @@ -261,14 +261,7 @@ impl<'a> Parser<'a> { module_span = module_span.merge(var.span); - let value = self - .modules - .get(module) - .ok_or(( - format!("There is no module with the namespace \"{}\".", module), - module_span, - ))? - .get_var(var)?; + let value = self.modules.get(module.into(), module_span)?.get_var(var)?; HigherIntermediateValue::Literal(value.clone()) } else { let fn_name = self @@ -277,11 +270,7 @@ impl<'a> Parser<'a> { let function = self .modules - .get(module) - .ok_or(( - format!("There is no module with the namespace \"{}\".", module), - module_span, - ))? + .get(module.into(), module_span)? .get_fn(fn_name.node) .ok_or(("Undefined function.", fn_name.span))?; @@ -341,13 +330,7 @@ impl<'a> Parser<'a> { } let as_ident = Identifier::from(&s); - let func = match self.scopes.get_fn( - Spanned { - node: as_ident, - span, - }, - self.global_scope, - ) { + let func = match self.scopes.get_fn(as_ident, self.global_scope) { Some(f) => f, None => { if let Some(f) = GLOBAL_FUNCTIONS.get(as_ident.as_str()) { diff --git a/src/scope.rs b/src/scope.rs index b5f3db9..ddf3340 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -230,17 +230,13 @@ impl Scopes { } } - pub fn get_fn<'a>( - &'a self, - name: Spanned, - global_scope: &'a Scope, - ) -> Option { + pub fn get_fn<'a>(&'a self, name: Identifier, global_scope: &'a Scope) -> Option { for scope in self.0.iter().rev() { - if scope.fn_exists(name.node) { - return scope.get_fn(name.node); + if scope.fn_exists(name) { + 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 { diff --git a/tests/get-function.rs b/tests/get-function.rs index 31583f6..2ec4e9f 100644 --- a/tests/get-function.rs +++ b/tests/get-function.rs @@ -121,3 +121,8 @@ test!( "a {\n color: call(call(get-function(get-function), darken), red, 10%);\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" +);