From aea7c9c408b8e710747e6669888e04f199965f22 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Mon, 22 Jun 2020 11:35:15 -0400 Subject: [PATCH] deny functions with reserved names or in control flow --- src/parse/function.rs | 46 +++++++++++++++++++++++++++++++++++-------- tests/functions.rs | 9 +++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/parse/function.rs b/src/parse/function.rs index 5ca1dde..d6753b9 100644 --- a/src/parse/function.rs +++ b/src/parse/function.rs @@ -14,18 +14,48 @@ use crate::{ use super::{NeverEmptyVec, Parser, Stmt}; +/// Names that functions are not allowed to have +const FORBIDDEN_IDENTIFIERS: [&str; 7] = + ["calc", "element", "expression", "url", "and", "or", "not"]; + +fn unvendor<'a>(name: &'a str) -> &'a str { + let mut chars = name.chars(); + if !matches!(chars.next(), Some('-')) { + return name; + } + if matches!(chars.next(), Some('-')) { + return name; + } + if name.chars().count() < 2 { + return name; + } + let mut pos = 2; + for c in chars { + if c == '-' { + return &name[pos..]; + } + pos += 1; + } + name +} + impl<'a> Parser<'a> { pub(super) fn parse_function(&mut self) -> SassResult<()> { - if self.in_mixin { - return Err(( - "Mixins may not contain function declarations.", - self.span_before, - ) - .into()); - } - self.whitespace_or_comment(); let Spanned { node: name, span } = self.parse_identifier()?; + + if self.in_mixin { + return Err(("Mixins may not contain function declarations.", span).into()); + } + + if self.in_control_flow { + return Err(("Functions may not be declared in control directives.", span).into()); + } + + if FORBIDDEN_IDENTIFIERS.contains(&unvendor(&name)) { + return Err(("Invalid function name.", span).into()); + } + self.whitespace_or_comment(); let args = match self.toks.next() { Some(Token { kind: '(', .. }) => self.parse_func_args()?, diff --git a/tests/functions.rs b/tests/functions.rs index 783a040..e58f982 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -121,3 +121,12 @@ test!( }", "a {\n color: \"success!\";\n}\n" ); +error!( + denies_function_declaration_in_control_flow, + "@if true {\n @function foo() {}\n}\n", + "Error: Functions may not be declared in control directives." +); +error!( + denies_function_declaration_with_reserved_name, + "@function url() {}", "Error: Invalid function name." +);