Refactor error handling
This commit is contained in:
parent
6d0686866e
commit
f817598a9d
@ -9,15 +9,15 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "hsl", |args, _| {
|
decl!(f "hsl", |args, _| {
|
||||||
let hue = match arg!(args, 0, "hue").eval() {
|
let hue = match arg!(args, 0, "hue").eval() {
|
||||||
Value::Dimension(n, _) => n,
|
Value::Dimension(n, _) => n,
|
||||||
_ => todo!("$hue: ____ is not a number."),
|
v => return Err(format!("$hue: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let saturation = match arg!(args, 1, "saturation").eval() {
|
let saturation = match arg!(args, 1, "saturation").eval() {
|
||||||
Value::Dimension(n, _) => n / Number::from(100),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
_ => todo!("$saturation: ____ is not a number."),
|
v => return Err(format!("$saturation: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let luminance = match arg!(args, 2, "luminance").eval() {
|
let luminance = match arg!(args, 2, "luminance").eval() {
|
||||||
Value::Dimension(n, _) => n / Number::from(100),
|
Value::Dimension(n, _) => n / Number::from(100),
|
||||||
_ => todo!("$luminance: ____ is not a number."),
|
v => return Err(format!("$luminance: {} is not a number.", v).into()),
|
||||||
};
|
};
|
||||||
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)) {
|
let alpha = match arg!(args, 3, "alpha"=Value::Dimension(Number::from(1), Unit::None)) {
|
||||||
Value::Dimension(n, Unit::None) => n,
|
Value::Dimension(n, Unit::None) => n,
|
||||||
|
20
src/error.rs
20
src/error.rs
@ -61,6 +61,26 @@ impl From<SassError> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for SassError {
|
||||||
|
#[inline]
|
||||||
|
fn from(error: &str) -> SassError {
|
||||||
|
SassError {
|
||||||
|
pos: Pos::new(),
|
||||||
|
message: error.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for SassError {
|
||||||
|
#[inline]
|
||||||
|
fn from(error: String) -> SassError {
|
||||||
|
SassError {
|
||||||
|
pos: Pos::new(),
|
||||||
|
message: error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Error for SassError {
|
impl Error for SassError {
|
||||||
fn description(&self) -> &'static str {
|
fn description(&self) -> &'static str {
|
||||||
"SASS parsing error"
|
"SASS parsing error"
|
||||||
|
27
src/lib.rs
27
src/lib.rs
@ -324,7 +324,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
| TokenKind::Symbol(Symbol::Mul)
|
| TokenKind::Symbol(Symbol::Mul)
|
||||||
| TokenKind::Symbol(Symbol::Percent)
|
| TokenKind::Symbol(Symbol::Percent)
|
||||||
| TokenKind::Symbol(Symbol::Period) => rules
|
| TokenKind::Symbol(Symbol::Period) => rules
|
||||||
.extend(self.eat_rules(&Selector(Vec::new()), &mut self.global_scope.clone())),
|
.extend(self.eat_rules(&Selector(Vec::new()), &mut self.global_scope.clone())?),
|
||||||
TokenKind::Whitespace(_) => {
|
TokenKind::Whitespace(_) => {
|
||||||
self.lexer.next();
|
self.lexer.next();
|
||||||
continue;
|
continue;
|
||||||
@ -348,8 +348,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
{
|
{
|
||||||
self.error(pos, "unexpected variable use at toplevel");
|
self.error(pos, "unexpected variable use at toplevel");
|
||||||
}
|
}
|
||||||
let VariableDecl { val, default } = eat_variable_value(&mut self.lexer, &self.global_scope)
|
let VariableDecl { val, default } = eat_variable_value(&mut self.lexer, &self.global_scope)?;
|
||||||
.unwrap_or_else(|err| self.error(err.0, &err.1));
|
|
||||||
if !default || self.global_scope.get_var(&name).is_err() {
|
if !default || self.global_scope.get_var(&name).is_err() {
|
||||||
self.global_scope.insert_var(&name, val);
|
self.global_scope.insert_var(&name, val);
|
||||||
}
|
}
|
||||||
@ -367,7 +366,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
rules.push(Stmt::MultilineComment(comment));
|
rules.push(Stmt::MultilineComment(comment));
|
||||||
}
|
}
|
||||||
TokenKind::AtRule(AtRuleKind::Include) => {
|
TokenKind::AtRule(AtRuleKind::Include) => {
|
||||||
rules.extend(eat_include(&mut self.lexer, &self.global_scope, &Selector(Vec::new())).unwrap_or_else(|e| self.error(e.0, &e.1)))
|
rules.extend(eat_include(&mut self.lexer, &self.global_scope, &Selector(Vec::new()))?)
|
||||||
}
|
}
|
||||||
TokenKind::AtRule(AtRuleKind::Import) => {
|
TokenKind::AtRule(AtRuleKind::Import) => {
|
||||||
let Token { pos, .. } = self
|
let Token { pos, .. } = self
|
||||||
@ -445,11 +444,9 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
Ok((rules, self.global_scope))
|
Ok((rules, self.global_scope))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_rules(&mut self, super_selector: &Selector, scope: &mut Scope) -> Vec<Stmt> {
|
fn eat_rules(&mut self, super_selector: &Selector, scope: &mut Scope) -> SassResult<Vec<Stmt>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector)
|
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector)? {
|
||||||
.unwrap_or_else(|error| self.error(error.0, &error.1))
|
|
||||||
{
|
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||||
#[allow(clippy::redundant_closure)]
|
#[allow(clippy::redundant_closure)]
|
||||||
@ -462,7 +459,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
}
|
}
|
||||||
Expr::Selector(s) => {
|
Expr::Selector(s) => {
|
||||||
self.scope += 1;
|
self.scope += 1;
|
||||||
let rules = self.eat_rules(&super_selector.zip(&s), scope);
|
let rules = self.eat_rules(&super_selector.zip(&s), scope)?;
|
||||||
stmts.push(Stmt::RuleSet(RuleSet {
|
stmts.push(Stmt::RuleSet(RuleSet {
|
||||||
super_selector: super_selector.clone(),
|
super_selector: super_selector.clone(),
|
||||||
selector: s,
|
selector: s,
|
||||||
@ -470,7 +467,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
}));
|
}));
|
||||||
self.scope -= 1;
|
self.scope -= 1;
|
||||||
if self.scope == 0 {
|
if self.scope == 0 {
|
||||||
return stmts;
|
return Ok(stmts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::VariableDecl(name, val) => {
|
Expr::VariableDecl(name, val) => {
|
||||||
@ -487,7 +484,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
|
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stmts
|
Ok(stmts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +492,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> Result<Option<Expr>, (Pos, String)> {
|
) -> SassResult<Option<Expr>> {
|
||||||
let mut values = Vec::with_capacity(5);
|
let mut values = Vec::with_capacity(5);
|
||||||
while let Some(tok) = toks.peek() {
|
while let Some(tok) = toks.peek() {
|
||||||
match &tok.kind {
|
match &tok.kind {
|
||||||
@ -520,7 +517,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
// in a style `color:red`. todo: refactor
|
// in a style `color:red`. todo: refactor
|
||||||
let mut v = values.into_iter().peekable();
|
let mut v = values.into_iter().peekable();
|
||||||
let property = Style::parse_property(&mut v, scope, super_selector, String::new());
|
let property = Style::parse_property(&mut v, scope, super_selector, String::new());
|
||||||
let value = Style::parse_value(&mut v, scope, super_selector);
|
let value = Style::parse_value(&mut v, scope, super_selector)?;
|
||||||
return Ok(Some(Expr::Style(Style { property, value })));
|
return Ok(Some(Expr::Style(Style { property, value })));
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
|
TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
|
||||||
@ -535,7 +532,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
let mut v = values.into_iter().peekable();
|
let mut v = values.into_iter().peekable();
|
||||||
let property =
|
let property =
|
||||||
Style::parse_property(&mut v, scope, super_selector, String::new());
|
Style::parse_property(&mut v, scope, super_selector, String::new());
|
||||||
let value = Style::parse_value(&mut v, scope, super_selector);
|
let value = Style::parse_value(&mut v, scope, super_selector)?;
|
||||||
return Ok(Some(Expr::Style(Style { property, value })));
|
return Ok(Some(Expr::Style(Style { property, value })));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -605,7 +602,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
AtRule::Charset(_) => todo!("@charset as expr"),
|
AtRule::Charset(_) => todo!("@charset as expr"),
|
||||||
AtRule::Debug(a, b) => Ok(Some(Expr::Debug(a, b))),
|
AtRule::Debug(a, b) => Ok(Some(Expr::Debug(a, b))),
|
||||||
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
||||||
AtRule::Error(a, b) => Err((a, b)),
|
AtRule::Error(pos, err) => Err(SassError::new(err, pos)),
|
||||||
AtRule::Return(_) => todo!("@return in unexpected location!"),
|
AtRule::Return(_) => todo!("@return in unexpected location!"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
15
src/mixin.rs
15
src/mixin.rs
@ -3,6 +3,7 @@ use std::vec::IntoIter;
|
|||||||
|
|
||||||
use crate::args::{eat_call_args, eat_func_args, CallArgs, FuncArgs};
|
use crate::args::{eat_call_args, eat_func_args, CallArgs, FuncArgs};
|
||||||
use crate::common::{Pos, Scope, Symbol};
|
use crate::common::{Pos, Scope, Symbol};
|
||||||
|
use crate::error::{SassError, SassResult};
|
||||||
use crate::selector::Selector;
|
use crate::selector::Selector;
|
||||||
use crate::utils::devour_whitespace;
|
use crate::utils::devour_whitespace;
|
||||||
use crate::{eat_expr, Expr, RuleSet, Stmt, Token, TokenKind};
|
use crate::{eat_expr, Expr, RuleSet, Stmt, Token, TokenKind};
|
||||||
@ -87,11 +88,11 @@ impl Mixin {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(mut self, super_selector: &Selector) -> Result<Vec<Stmt>, (Pos, String)> {
|
pub fn call(mut self, super_selector: &Selector) -> SassResult<Vec<Stmt>> {
|
||||||
self.eval(super_selector)
|
self.eval(super_selector)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, super_selector: &Selector) -> Result<Vec<Stmt>, (Pos, String)> {
|
fn eval(&mut self, super_selector: &Selector) -> SassResult<Vec<Stmt>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(&mut self.body, &self.scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.body, &self.scope, super_selector)? {
|
||||||
match expr {
|
match expr {
|
||||||
@ -123,7 +124,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> Result<Vec<Stmt>, (Pos, String)> {
|
) -> SassResult<Vec<Stmt>> {
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let Token { kind, pos } = toks
|
let Token { kind, pos } = toks
|
||||||
@ -131,7 +132,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
.expect("this must exist because we have already peeked");
|
.expect("this must exist because we have already peeked");
|
||||||
let name = match kind {
|
let name = match kind {
|
||||||
TokenKind::Ident(s) => s,
|
TokenKind::Ident(s) => s,
|
||||||
_ => return Err((pos, String::from("Expected identifier."))),
|
_ => return Err(SassError::new("Expected identifier.", pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
@ -147,17 +148,17 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
tmp
|
tmp
|
||||||
}
|
}
|
||||||
_ => return Err((pos, String::from("expected `(` or `;`"))),
|
_ => return Err(SassError::new("expected `(` or `;`", pos)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err((pos, String::from("unexpected EOF")));
|
return Err(SassError::new("unexpected EOF", pos));
|
||||||
};
|
};
|
||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let mixin = match scope.get_mixin(&name) {
|
let mixin = match scope.get_mixin(&name) {
|
||||||
Ok(m) => m.clone(),
|
Ok(m) => m.clone(),
|
||||||
_ => return Err((pos, String::from("Expected identifier."))),
|
_ => return Err(SassError::new("Expected identifier.", pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let rules = mixin.args(&args).call(super_selector)?;
|
let rules = mixin.args(&args).call(super_selector)?;
|
||||||
|
15
src/style.rs
15
src/style.rs
@ -1,4 +1,5 @@
|
|||||||
use crate::common::{Pos, Scope, Symbol};
|
use crate::common::{Pos, Scope, Symbol};
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::selector::Selector;
|
use crate::selector::Selector;
|
||||||
use crate::utils::{devour_whitespace, parse_interpolation};
|
use crate::utils::{devour_whitespace, parse_interpolation};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
@ -33,7 +34,7 @@ impl Style {
|
|||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> Value {
|
) -> SassResult<Value> {
|
||||||
StyleParser::new(scope, super_selector).parse_style_value(toks)
|
StyleParser::new(scope, super_selector).parse_style_value(toks)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ impl Style {
|
|||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
super_property: String,
|
super_property: String,
|
||||||
) -> Result<Expr, (Pos, String)> {
|
) -> SassResult<Expr> {
|
||||||
StyleParser::new(scope, super_selector).eat_style_group(toks, super_property)
|
StyleParser::new(scope, super_selector).eat_style_group(toks, super_property)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +64,7 @@ impl<'a> StyleParser<'a> {
|
|||||||
pub(crate) fn parse_style_value<I: Iterator<Item = Token>>(
|
pub(crate) fn parse_style_value<I: Iterator<Item = Token>>(
|
||||||
&self,
|
&self,
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
) -> Value {
|
) -> SassResult<Value> {
|
||||||
let mut style = Vec::new();
|
let mut style = Vec::new();
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
@ -99,14 +100,14 @@ impl<'a> StyleParser<'a> {
|
|||||||
style.push(toks.next().unwrap());
|
style.push(toks.next().unwrap());
|
||||||
}
|
}
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
Value::from_tokens(&mut style.into_iter().peekable(), self.scope).unwrap()
|
Value::from_tokens(&mut style.into_iter().peekable(), self.scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eat_style_group<I: Iterator<Item = Token>>(
|
pub(crate) fn eat_style_group<I: Iterator<Item = Token>>(
|
||||||
&self,
|
&self,
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
super_property: String,
|
super_property: String,
|
||||||
) -> Result<Expr, (Pos, String)> {
|
) -> SassResult<Expr> {
|
||||||
let mut styles = Vec::new();
|
let mut styles = Vec::new();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
while let Some(tok) = toks.peek() {
|
while let Some(tok) = toks.peek() {
|
||||||
@ -138,7 +139,7 @@ impl<'a> StyleParser<'a> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let value = self.parse_style_value(toks);
|
let value = self.parse_style_value(toks)?;
|
||||||
styles.push(Style { property, value });
|
styles.push(Style { property, value });
|
||||||
if let Some(tok) = toks.peek() {
|
if let Some(tok) = toks.peek() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
@ -153,7 +154,7 @@ impl<'a> StyleParser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let val = self.parse_style_value(toks);
|
let val = self.parse_style_value(toks)?;
|
||||||
return Ok(Expr::Style(Style {
|
return Ok(Expr::Style(Style {
|
||||||
property: super_property,
|
property: super_property,
|
||||||
value: val,
|
value: val,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::common::{Keyword, Pos, Symbol};
|
use crate::common::{Keyword, Symbol};
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Lexer;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{Scope, Token, TokenKind};
|
use crate::{Scope, Token, TokenKind};
|
||||||
@ -81,7 +82,7 @@ impl VariableDecl {
|
|||||||
pub(crate) fn eat_variable_value<I: Iterator<Item = Token>>(
|
pub(crate) fn eat_variable_value<I: Iterator<Item = Token>>(
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Result<VariableDecl, (Pos, String)> {
|
) -> SassResult<VariableDecl> {
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let mut default = false;
|
let mut default = false;
|
||||||
let mut raw: Vec<Token> = Vec::new();
|
let mut raw: Vec<Token> = Vec::new();
|
||||||
|
@ -9,6 +9,7 @@ use crate::args::eat_call_args;
|
|||||||
use crate::builtin::GLOBAL_FUNCTIONS;
|
use crate::builtin::GLOBAL_FUNCTIONS;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::common::{Keyword, ListSeparator, Op, QuoteKind, Scope, Symbol};
|
use crate::common::{Keyword, ListSeparator, Op, QuoteKind, Scope, Symbol};
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::units::Unit;
|
use crate::units::Unit;
|
||||||
use crate::utils::{devour_whitespace_or_comment, parse_interpolation};
|
use crate::utils::{devour_whitespace_or_comment, parse_interpolation};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
@ -83,25 +84,25 @@ impl Value {
|
|||||||
pub fn from_tokens<I: Iterator<Item = Token>>(
|
pub fn from_tokens<I: Iterator<Item = Token>>(
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Option<Self> {
|
) -> SassResult<Self> {
|
||||||
let left = Self::_from_tokens(toks, scope)?;
|
let left = Self::_from_tokens(toks, scope)?;
|
||||||
let whitespace = devour_whitespace_or_comment(toks);
|
let whitespace = devour_whitespace_or_comment(toks);
|
||||||
let next = match toks.peek() {
|
let next = match toks.peek() {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => return Some(left),
|
None => return Ok(left),
|
||||||
};
|
};
|
||||||
match next.kind {
|
match next.kind {
|
||||||
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseParen) => {
|
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseParen) => {
|
||||||
Some(left)
|
Ok(left)
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::Comma) => {
|
TokenKind::Symbol(Symbol::Comma) => {
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
let right = match Self::from_tokens(toks, scope) {
|
let right = match Self::from_tokens(toks, scope) {
|
||||||
Some(x) => x,
|
Ok(x) => x,
|
||||||
None => return Some(left),
|
Err(_) => return Ok(left),
|
||||||
};
|
};
|
||||||
Some(Value::List(vec![left, right], ListSeparator::Comma))
|
Ok(Value::List(vec![left, right], ListSeparator::Comma))
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::Plus)
|
TokenKind::Symbol(Symbol::Plus)
|
||||||
| TokenKind::Symbol(Symbol::Minus)
|
| TokenKind::Symbol(Symbol::Minus)
|
||||||
@ -121,18 +122,18 @@ impl Value {
|
|||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
let right = match Self::from_tokens(toks, scope) {
|
let right = match Self::from_tokens(toks, scope) {
|
||||||
Some(x) => x,
|
Ok(x) => x,
|
||||||
None => return Some(left),
|
Err(_) => return Ok(left),
|
||||||
};
|
};
|
||||||
Some(Value::BinaryOp(Box::new(left), op, Box::new(right)))
|
Ok(Value::BinaryOp(Box::new(left), op, Box::new(right)))
|
||||||
}
|
}
|
||||||
_ if whitespace => {
|
_ if whitespace => {
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
let right = match Self::from_tokens(toks, scope) {
|
let right = match Self::from_tokens(toks, scope) {
|
||||||
Some(x) => x,
|
Ok(x) => x,
|
||||||
None => return Some(left),
|
Err(_) => return Ok(left),
|
||||||
};
|
};
|
||||||
Some(Value::List(vec![left, right], ListSeparator::Space))
|
Ok(Value::List(vec![left, right], ListSeparator::Space))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
dbg!(&next.kind);
|
dbg!(&next.kind);
|
||||||
@ -144,11 +145,11 @@ impl Value {
|
|||||||
fn _from_tokens<I: Iterator<Item = Token>>(
|
fn _from_tokens<I: Iterator<Item = Token>>(
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Option<Self> {
|
) -> SassResult<Self> {
|
||||||
let kind = if let Some(tok) = toks.next() {
|
let kind = if let Some(tok) = toks.next() {
|
||||||
tok.kind
|
tok.kind
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return Err("Unexpected EOF".into());
|
||||||
};
|
};
|
||||||
match kind {
|
match kind {
|
||||||
TokenKind::Number(val) => {
|
TokenKind::Number(val) => {
|
||||||
@ -187,7 +188,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
BigRational::new(num.parse().unwrap(), pow(BigInt::from(10), num_dec))
|
BigRational::new(num.parse().unwrap(), pow(BigInt::from(10), num_dec))
|
||||||
};
|
};
|
||||||
Some(Value::Dimension(Number::new(n), unit))
|
Ok(Value::Dimension(Number::new(n), unit))
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::OpenParen) => {
|
TokenKind::Symbol(Symbol::OpenParen) => {
|
||||||
devour_whitespace_or_comment(toks);
|
devour_whitespace_or_comment(toks);
|
||||||
@ -196,14 +197,14 @@ impl Value {
|
|||||||
toks.next().unwrap().kind,
|
toks.next().unwrap().kind,
|
||||||
TokenKind::Symbol(Symbol::CloseParen)
|
TokenKind::Symbol(Symbol::CloseParen)
|
||||||
);
|
);
|
||||||
Some(Value::Paren(Box::new(val)))
|
Ok(Value::Paren(Box::new(val)))
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::BitAnd) => {
|
TokenKind::Symbol(Symbol::BitAnd) => {
|
||||||
Some(Value::Ident(String::from("&"), QuoteKind::None))
|
Ok(Value::Ident(String::from("&"), QuoteKind::None))
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::Hash) => Some(parse_hex(flatten_ident(toks, scope))),
|
TokenKind::Symbol(Symbol::Hash) => Ok(parse_hex(flatten_ident(toks, scope))),
|
||||||
// TokenKind::Interpolation => {
|
// TokenKind::Interpolation => {
|
||||||
// Some(Value::Ident(
|
// Ok(Value::Ident(
|
||||||
// parse_interpolation(toks, scope)
|
// parse_interpolation(toks, scope)
|
||||||
// .iter()
|
// .iter()
|
||||||
// .map(|x| x.kind.to_string())
|
// .map(|x| x.kind.to_string())
|
||||||
@ -222,7 +223,7 @@ impl Value {
|
|||||||
let func = match scope.get_fn(&s) {
|
let func = match scope.get_fn(&s) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
||||||
Some(f) => return f(&eat_call_args(toks, scope), scope).ok(),
|
Some(f) => return f(&eat_call_args(toks, scope), scope),
|
||||||
None => {
|
None => {
|
||||||
s.push('(');
|
s.push('(');
|
||||||
let mut unclosed_parens = 0;
|
let mut unclosed_parens = 0;
|
||||||
@ -255,17 +256,17 @@ impl Value {
|
|||||||
}
|
}
|
||||||
s.push_str(&t.kind.to_string());
|
s.push_str(&t.kind.to_string());
|
||||||
}
|
}
|
||||||
return Some(Value::Ident(s, QuoteKind::None));
|
return Ok(Value::Ident(s, QuoteKind::None));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Some(func.clone().args(&eat_call_args(toks, scope)).call())
|
Ok(func.clone().args(&eat_call_args(toks, scope)).call())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Ok(c) = crate::color::ColorName::try_from(s.as_ref()) {
|
if let Ok(c) = crate::color::ColorName::try_from(s.as_ref()) {
|
||||||
Some(Value::Color(c.into_color(s)))
|
Ok(Value::Color(c.into_color(s)))
|
||||||
} else {
|
} else {
|
||||||
Some(Value::Ident(s, QuoteKind::None))
|
Ok(Value::Ident(s, QuoteKind::None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
s.push_str(&tok.kind.to_string());
|
s.push_str(&tok.kind.to_string());
|
||||||
}
|
}
|
||||||
Some(Value::Ident(s, QuoteKind::Double))
|
Ok(Value::Ident(s, QuoteKind::Double))
|
||||||
}
|
}
|
||||||
TokenKind::Symbol(Symbol::SingleQuote) => {
|
TokenKind::Symbol(Symbol::SingleQuote) => {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
@ -295,10 +296,10 @@ impl Value {
|
|||||||
}
|
}
|
||||||
s.push_str(&tok.kind.to_string());
|
s.push_str(&tok.kind.to_string());
|
||||||
}
|
}
|
||||||
Some(Value::Ident(s, QuoteKind::Single))
|
Ok(Value::Ident(s, QuoteKind::Single))
|
||||||
}
|
}
|
||||||
TokenKind::Variable(ref v) => {
|
TokenKind::Variable(ref v) => {
|
||||||
Some(scope.get_var(v).expect("expected variable").clone())
|
Ok(scope.get_var(v).expect("expected variable").clone())
|
||||||
}
|
}
|
||||||
TokenKind::Interpolation => {
|
TokenKind::Interpolation => {
|
||||||
let mut s = parse_interpolation(toks, scope)
|
let mut s = parse_interpolation(toks, scope)
|
||||||
@ -323,13 +324,13 @@ impl Value {
|
|||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Value::Ident(s, QuoteKind::None))
|
Ok(Value::Ident(s, QuoteKind::None))
|
||||||
}
|
}
|
||||||
TokenKind::Keyword(Keyword::Important) => Some(Value::Important),
|
TokenKind::Keyword(Keyword::Important) => Ok(Value::Important),
|
||||||
TokenKind::Keyword(Keyword::True) => Some(Value::True),
|
TokenKind::Keyword(Keyword::True) => Ok(Value::True),
|
||||||
TokenKind::Keyword(Keyword::False) => Some(Value::False),
|
TokenKind::Keyword(Keyword::False) => Ok(Value::False),
|
||||||
TokenKind::Keyword(Keyword::Null) => Some(Value::Null),
|
TokenKind::Keyword(Keyword::Null) => Ok(Value::Null),
|
||||||
_ => None,
|
_ => Err("Unexpected token in value parsing".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user