diff --git a/src/common.rs b/src/common.rs index b343d0b..2e85755 100644 --- a/src/common.rs +++ b/src/common.rs @@ -76,7 +76,7 @@ impl Display for Symbol { Self::At => write!(f, "@"), Self::Dollar => write!(f, "$"), Self::OpenParen => write!(f, "("), - Self::CloseParen => write!(f, "),"), + Self::CloseParen => write!(f, ")"), Self::OpenCurlyBrace => write!(f, "{{"), Self::CloseCurlyBrace => write!(f, "}}"), Self::OpenSquareBrace => write!(f, "["), diff --git a/src/value/number.rs b/src/value/number.rs index 3921b62..95820a1 100644 --- a/src/value/number.rs +++ b/src/value/number.rs @@ -81,7 +81,7 @@ impl Display for Number { let mut frac = self.val.fract(); if frac != BigRational::from_integer(BigInt::from(0)) { f.write_char('.')?; - for _ in 0..(PRECISION-1) { + for _ in 0..(PRECISION - 1) { frac *= BigRational::from_integer(BigInt::from(10)); write!(f, "{}", frac.to_integer())?; frac = frac.fract(); diff --git a/src/value/ops.rs b/src/value/ops.rs index da214b4..e9284ad 100644 --- a/src/value/ops.rs +++ b/src/value/ops.rs @@ -22,6 +22,13 @@ impl Add for Value { }, Self::Dimension(num, unit) => match other { Self::Dimension(num2, unit2) => Value::Dimension(num + num2, unit), + Self::Ident(s, q) => { + let quotes = match q { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident(format!("{}{}{}", num, unit, s), quotes) + } _ => todo!(), }, // Self::List(..) => todo!(), diff --git a/src/value/parse.rs b/src/value/parse.rs index 395e7ae..1cd879b 100644 --- a/src/value/parse.rs +++ b/src/value/parse.rs @@ -219,15 +219,47 @@ impl Value { .. }) => { toks.next(); - let args = eat_call_args(toks, scope); let func = match scope.get_fn(&s) { Ok(f) => f, Err(_) => match GLOBAL_FUNCTIONS.get(&s) { - Some(f) => return f(&args, scope), - None => todo!("called undefined function"), + Some(f) => return f(&eat_call_args(toks, scope), scope), + None => { + s.push('('); + let mut unclosed_parens = 0; + while let Some(t) = toks.next() { + match &t.kind { + TokenKind::Symbol(Symbol::OpenParen) => { + unclosed_parens += 1; + } + TokenKind::Interpolation => s.push_str( + &parse_interpolation(toks, scope) + .iter() + .map(|x| x.kind.to_string()) + .collect::(), + ), + TokenKind::Variable(v) => s.push_str( + &scope + .get_var(v) + .expect("expected variable to exist") + .to_string(), + ), + TokenKind::Symbol(Symbol::CloseParen) => { + if unclosed_parens <= 1 { + s.push(')'); + break; + } else { + unclosed_parens -= 1; + } + } + _ => {} + } + s.push_str(&t.kind.to_string()); + } + return Some(Value::Ident(s, QuoteKind::None)); + } }, }; - Some(func.clone().args(&args).call()) + Some(func.clone().args(&eat_call_args(toks, scope)).call()) } _ => { if let Ok(c) = crate::color::ColorName::try_from(s.as_ref()) { diff --git a/tests/values.rs b/tests/values.rs index a16dca6..aace14c 100644 --- a/tests/values.rs +++ b/tests/values.rs @@ -294,3 +294,12 @@ test!( "a {\n color: 'foo' - 1px;\n}\n", "a {\n color: \"foo\"-1px;\n}\n" ); +test!( + undefined_function_call_is_ident, + "a {\n color: foo();\n}\n" +); +test!( + undefined_function_call_is_ident_adds, + "a {\n color: 1 + foo();\n}\n", + "a {\n color: 1foo();\n}\n" +);