Refactor error handling

This commit is contained in:
ConnorSkees 2020-02-16 10:54:25 -05:00
parent 6d0686866e
commit f817598a9d
7 changed files with 88 additions and 67 deletions

View File

@ -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,

View File

@ -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"

View File

@ -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!"),
}; };
} }

View File

@ -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)?;

View File

@ -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,

View File

@ -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();

View File

@ -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()),
} }
} }
} }