Handle variables as parameters to function calls
This commit is contained in:
parent
4cbbff259c
commit
709ed5c6b5
111
src/args.rs
111
src/args.rs
@ -1,8 +1,9 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use crate::common::Symbol;
|
use crate::common::{Scope, Symbol};
|
||||||
use crate::utils::devour_whitespace;
|
use crate::utils::devour_whitespace;
|
||||||
|
use crate::value::Value;
|
||||||
use crate::{Token, TokenKind};
|
use crate::{Token, TokenKind};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
@ -11,7 +12,7 @@ pub(crate) struct FuncArgs(pub Vec<FuncArg>);
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub(crate) struct FuncArg {
|
pub(crate) struct FuncArg {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub default: Option<Vec<Token>>,
|
pub default: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncArgs {
|
impl FuncArgs {
|
||||||
@ -21,7 +22,7 @@ impl FuncArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, std::default::Default)]
|
#[derive(Debug, Clone, std::default::Default)]
|
||||||
pub(crate) struct CallArgs(pub BTreeMap<String, Vec<Token>>);
|
pub(crate) struct CallArgs(pub BTreeMap<String, Value>);
|
||||||
|
|
||||||
impl CallArgs {
|
impl CallArgs {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -32,12 +33,15 @@ impl CallArgs {
|
|||||||
self.0.is_empty()
|
self.0.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, val: &str) -> Option<&Vec<Token>> {
|
pub fn get(&self, val: &str) -> Option<&Value> {
|
||||||
self.0.get(val)
|
self.0.get(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -> FuncArgs {
|
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
|
||||||
|
toks: &mut Peekable<I>,
|
||||||
|
scope: &Scope,
|
||||||
|
) -> FuncArgs {
|
||||||
let mut args: Vec<FuncArg> = Vec::new();
|
let mut args: Vec<FuncArg> = Vec::new();
|
||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
@ -62,14 +66,20 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -
|
|||||||
toks.next();
|
toks.next();
|
||||||
args.push(FuncArg {
|
args.push(FuncArg {
|
||||||
name,
|
name,
|
||||||
default: Some(default),
|
default: Some(
|
||||||
|
Value::from_tokens(&mut default.into_iter().peekable(), scope)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::CloseParen) => {
|
TokenKind::Symbol(Symbol::CloseParen) => {
|
||||||
args.push(FuncArg {
|
args.push(FuncArg {
|
||||||
name,
|
name,
|
||||||
default: Some(default),
|
default: Some(
|
||||||
|
Value::from_tokens(&mut default.into_iter().peekable(), scope)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -87,7 +97,9 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -
|
|||||||
default: if default.is_empty() {
|
default: if default.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(default)
|
Some(
|
||||||
|
Value::from_tokens(&mut default.into_iter().peekable(), scope).unwrap(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -112,21 +124,70 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -
|
|||||||
FuncArgs(args)
|
FuncArgs(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -> CallArgs {
|
pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
||||||
let mut args: BTreeMap<String, Vec<Token>> = BTreeMap::new();
|
toks: &mut Peekable<I>,
|
||||||
|
scope: &Scope,
|
||||||
|
) -> CallArgs {
|
||||||
|
let mut args: BTreeMap<String, Value> = BTreeMap::new();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let mut name: Option<String> = None;
|
let mut name: Option<String> = None;
|
||||||
let mut val = Vec::new();
|
let mut val = Vec::new();
|
||||||
while let Some(Token { kind, pos }) = toks.next() {
|
while let Some(Token { kind, pos }) = toks.next() {
|
||||||
match kind {
|
match kind {
|
||||||
TokenKind::Variable(v) => name = Some(v),
|
TokenKind::Variable(v) => {
|
||||||
|
devour_whitespace(toks);
|
||||||
|
match toks.peek() {
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenKind::Symbol(Symbol::Colon),
|
||||||
|
..
|
||||||
|
}) => name = Some(v),
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenKind::Symbol(Symbol::Comma),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
toks.next();
|
||||||
|
match name {
|
||||||
|
Some(ref name) => {
|
||||||
|
args.insert(name.clone(), scope.vars.get(&v).unwrap().clone())
|
||||||
|
}
|
||||||
|
None => args.insert(
|
||||||
|
format!("{}", args.len()),
|
||||||
|
scope.vars.get(&v).unwrap().clone(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
if let Some(ref mut s) = name {
|
||||||
|
s.clear();
|
||||||
|
}
|
||||||
|
val.clear();
|
||||||
|
}
|
||||||
|
Some(Token {
|
||||||
|
kind: TokenKind::Symbol(Symbol::CloseParen),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
toks.next();
|
||||||
|
match name {
|
||||||
|
Some(name) => args.insert(name, scope.vars.get(&v).unwrap().clone()),
|
||||||
|
None => args.insert(
|
||||||
|
format!("{}", args.len()),
|
||||||
|
scope.vars.get(&v).unwrap().clone(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => todo!("unexpected token after variable in call args"),
|
||||||
|
}
|
||||||
|
}
|
||||||
TokenKind::Symbol(Symbol::Colon) => {
|
TokenKind::Symbol(Symbol::Colon) => {
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
while let Some(tok) = toks.peek() {
|
while let Some(tok) = toks.peek() {
|
||||||
match &tok.kind {
|
match &tok.kind {
|
||||||
TokenKind::Symbol(Symbol::Comma) => {
|
TokenKind::Symbol(Symbol::Comma) => {
|
||||||
toks.next();
|
toks.next();
|
||||||
args.insert(name.clone().unwrap(), val.clone());
|
args.insert(
|
||||||
|
name.clone().unwrap(),
|
||||||
|
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
if let Some(ref mut s) = name {
|
if let Some(ref mut s) = name {
|
||||||
s.clear();
|
s.clear();
|
||||||
}
|
}
|
||||||
@ -134,7 +195,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::CloseParen) => {
|
TokenKind::Symbol(Symbol::CloseParen) => {
|
||||||
args.insert(name.clone().unwrap(), val.clone());
|
args.insert(
|
||||||
|
name.clone().unwrap(),
|
||||||
|
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => val.push(toks.next().expect("we know this exists!")),
|
_ => val.push(toks.next().expect("we know this exists!")),
|
||||||
@ -143,15 +208,27 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -
|
|||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::CloseParen) => {
|
TokenKind::Symbol(Symbol::CloseParen) => {
|
||||||
match name {
|
match name {
|
||||||
Some(name) => args.insert(name, val),
|
Some(name) => args.insert(
|
||||||
None => args.insert(format!("{}", args.len()), val),
|
name,
|
||||||
|
Value::from_tokens(&mut val.into_iter().peekable(), scope).unwrap(),
|
||||||
|
),
|
||||||
|
None => args.insert(
|
||||||
|
format!("{}", args.len()),
|
||||||
|
Value::from_tokens(&mut val.into_iter().peekable(), scope).unwrap(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::Comma) => {
|
TokenKind::Symbol(Symbol::Comma) => {
|
||||||
match name {
|
match name {
|
||||||
Some(ref name) => args.insert(name.clone(), val.clone()),
|
Some(ref name) => args.insert(
|
||||||
None => args.insert(format!("{}", args.len()), val.clone()),
|
name.clone(),
|
||||||
|
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope).unwrap(),
|
||||||
|
),
|
||||||
|
None => args.insert(
|
||||||
|
format!("{}", args.len()),
|
||||||
|
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope).unwrap(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
if let Some(ref mut s) = name {
|
if let Some(ref mut s) = name {
|
||||||
s.clear();
|
s.clear();
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::default::Default;
|
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
use crate::mixin::Mixin;
|
use crate::mixin::Mixin;
|
||||||
use crate::Token;
|
use crate::value::Value;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Symbol {
|
pub enum Symbol {
|
||||||
@ -337,9 +336,9 @@ impl Display for Pos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Scope {
|
pub(crate) struct Scope {
|
||||||
pub vars: HashMap<String, Vec<Token>>,
|
pub vars: HashMap<String, Value>,
|
||||||
pub mixins: HashMap<String, Mixin>,
|
pub mixins: HashMap<String, Mixin>,
|
||||||
pub functions: HashMap<String, Function>,
|
pub functions: HashMap<String, Function>,
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl Function {
|
|||||||
Some(Token {
|
Some(Token {
|
||||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||||
..
|
..
|
||||||
}) => eat_func_args(toks),
|
}) => eat_func_args(toks, scope),
|
||||||
_ => return Err((pos, String::from("expected `(` after function declaration"))),
|
_ => return Err((pos, String::from("expected `(` after function declaration"))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ use crate::mixin::{eat_include, Mixin};
|
|||||||
use crate::selector::{Attribute, Selector};
|
use crate::selector::{Attribute, Selector};
|
||||||
use crate::style::Style;
|
use crate::style::Style;
|
||||||
use crate::utils::{devour_whitespace, eat_variable_value, IsComment, IsWhitespace};
|
use crate::utils::{devour_whitespace, eat_variable_value, IsComment, IsWhitespace};
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod atrule;
|
mod atrule;
|
||||||
@ -200,7 +201,7 @@ enum Expr {
|
|||||||
/// A full selector `a > h1`
|
/// A full selector `a > h1`
|
||||||
Selector(Selector),
|
Selector(Selector),
|
||||||
/// A variable declaration `$var: 1px`
|
/// A variable declaration `$var: 1px`
|
||||||
VariableDecl(String, Vec<Token>),
|
VariableDecl(String, Value),
|
||||||
/// A mixin declaration `@mixin foo {}`
|
/// A mixin declaration `@mixin foo {}`
|
||||||
MixinDecl(String, Mixin),
|
MixinDecl(String, Mixin),
|
||||||
FunctionDecl(String, Function),
|
FunctionDecl(String, Function),
|
||||||
|
@ -42,7 +42,7 @@ impl Mixin {
|
|||||||
Some(Token {
|
Some(Token {
|
||||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||||
..
|
..
|
||||||
}) => eat_func_args(toks),
|
}) => eat_func_args(toks, scope),
|
||||||
Some(Token {
|
Some(Token {
|
||||||
kind: TokenKind::Symbol(Symbol::OpenCurlyBrace),
|
kind: TokenKind::Symbol(Symbol::OpenCurlyBrace),
|
||||||
..
|
..
|
||||||
@ -137,7 +137,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
let args = if let Some(tok) = toks.next() {
|
let args = if let Some(tok) = toks.next() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
TokenKind::Symbol(Symbol::SemiColon) => CallArgs::new(),
|
TokenKind::Symbol(Symbol::SemiColon) => CallArgs::new(),
|
||||||
TokenKind::Symbol(Symbol::OpenParen) => eat_call_args(toks),
|
TokenKind::Symbol(Symbol::OpenParen) => eat_call_args(toks, scope),
|
||||||
_ => return Err((pos, String::from("expected `(` or `;`"))),
|
_ => return Err((pos, String::from("expected `(` or `;`"))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user