refactor parsing of toplevel variables

This commit is contained in:
ConnorSkees 2020-05-21 13:25:37 -04:00
parent 6b9f68922f
commit c68576bb23
3 changed files with 35 additions and 34 deletions

View File

@ -22,7 +22,7 @@ use crate::selector::Selector;
use crate::token::Token; use crate::token::Token;
use crate::utils::{ use crate::utils::{
devour_whitespace, eat_comment, eat_ident, eat_variable_value, parse_quoted_string, devour_whitespace, eat_comment, eat_ident, eat_variable_value, parse_quoted_string,
read_until_newline, VariableDecl, peek_ident_no_interpolation, peek_whitespace, read_until_newline, VariableDecl,
}; };
use crate::{eat_expr, Expr, RuleSet, Stmt}; use crate::{eat_expr, Expr, RuleSet, Stmt};
@ -79,7 +79,7 @@ impl StyleSheet {
let file = map.add_file("stdin".into(), input); let file = map.add_file("stdin".into(), input);
Css::from_stylesheet(StyleSheet( Css::from_stylesheet(StyleSheet(
StyleSheetParser { StyleSheetParser {
lexer: Lexer::new(&file).peekmore(), lexer: &mut Lexer::new(&file).peekmore(),
nesting: 0, nesting: 0,
map: &mut map, map: &mut map,
path: Path::new(""), path: Path::new(""),
@ -111,7 +111,7 @@ impl StyleSheet {
let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?); let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?);
Css::from_stylesheet(StyleSheet( Css::from_stylesheet(StyleSheet(
StyleSheetParser { StyleSheetParser {
lexer: Lexer::new(&file).peekmore(), lexer: &mut Lexer::new(&file).peekmore(),
nesting: 0, nesting: 0,
map: &mut map, map: &mut map,
path: p.as_ref(), path: p.as_ref(),
@ -131,7 +131,7 @@ impl StyleSheet {
) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> { ) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
let file = map.add_file(p.clone().into(), String::from_utf8(fs::read(p)?)?); let file = map.add_file(p.clone().into(), String::from_utf8(fs::read(p)?)?);
Ok(StyleSheetParser { Ok(StyleSheetParser {
lexer: Lexer::new(&file).peekmore(), lexer: &mut Lexer::new(&file).peekmore(),
nesting: 0, nesting: 0,
map, map,
path: p.as_ref(), path: p.as_ref(),
@ -145,7 +145,7 @@ impl StyleSheet {
} }
struct StyleSheetParser<'a> { struct StyleSheetParser<'a> {
lexer: PeekMoreIterator<Lexer<'a>>, lexer: &'a mut PeekMoreIterator<Lexer<'a>>,
nesting: u32, nesting: u32,
map: &'a mut CodeMap, map: &'a mut CodeMap,
path: &'a Path, path: &'a Path,
@ -171,36 +171,35 @@ impl<'a> StyleSheetParser<'a> {
continue; continue;
} }
'$' => { '$' => {
let span_before = self.lexer.next().unwrap().pos(); self.lexer.next();
let name = eat_ident( let name = peek_ident_no_interpolation(self.lexer, false)?;
&mut self.lexer, let whitespace = peek_whitespace(self.lexer);
&Scope::new(),
&Selector::new(), match self.lexer.peek() {
span_before Some(Token { kind: ':', .. }) => {
)?; self.lexer.take(name.node.chars().count() + whitespace + 1)
devour_whitespace(&mut self.lexer); .for_each(drop);
let Token { kind, pos } = self devour_whitespace(self.lexer);
.lexer
.next() let VariableDecl { val, default, .. } =
.unwrap(); eat_variable_value(self.lexer, &Scope::new(), &Selector::new())?;
if kind != ':' {
return Err(("expected \":\".", pos).into()); if !(default && global_var_exists(&name)) {
} insert_global_var(&name.node, val)?;
let VariableDecl { val, default, .. } = }
eat_variable_value(&mut self.lexer, &Scope::new(), &Selector::new())?; }
if !(default && global_var_exists(&name)) { Some(..) | None => return Err(("expected \":\".", name.span).into()),
insert_global_var(&name.node, val)?;
} }
} }
'/' => { '/' => {
let pos = self.lexer.next().unwrap().pos; let pos = self.lexer.next().unwrap().pos;
match self.lexer.next() { match self.lexer.next() {
Some(Token { kind: '/', .. }) => { Some(Token { kind: '/', .. }) => {
read_until_newline(&mut self.lexer); read_until_newline(self.lexer);
devour_whitespace(&mut self.lexer); devour_whitespace(self.lexer);
} }
Some(Token { kind: '*', .. }) => { Some(Token { kind: '*', .. }) => {
let comment = eat_comment(&mut self.lexer, &Scope::new(), &Selector::new())?; let comment = eat_comment(self.lexer, &Scope::new(), &Selector::new())?;
rules.push(comment.map_node(Stmt::MultilineComment)); rules.push(comment.map_node(Stmt::MultilineComment));
} }
_ => return Err(("expected selector.", pos).into()) _ => return Err(("expected selector.", pos).into())
@ -209,7 +208,7 @@ impl<'a> StyleSheetParser<'a> {
'@' => { '@' => {
let span_before = self.lexer.next().unwrap().pos(); let span_before = self.lexer.next().unwrap().pos();
let Spanned { node: at_rule_kind, span } = eat_ident( let Spanned { node: at_rule_kind, span } = eat_ident(
&mut self.lexer, self.lexer,
&Scope::new(), &Scope::new(),
&Selector::new(), &Selector::new(),
span_before span_before
@ -219,14 +218,14 @@ impl<'a> StyleSheetParser<'a> {
} }
match AtRuleKind::from(at_rule_kind.as_str()) { match AtRuleKind::from(at_rule_kind.as_str()) {
AtRuleKind::Include => rules.extend(eat_include( AtRuleKind::Include => rules.extend(eat_include(
&mut self.lexer, self.lexer,
&Scope::new(), &Scope::new(),
&Selector::new(), &Selector::new(),
None, None,
span span
)?), )?),
AtRuleKind::Import => { AtRuleKind::Import => {
devour_whitespace(&mut self.lexer); devour_whitespace(self.lexer);
let mut file_name = String::new(); let mut file_name = String::new();
let next = match self.lexer.next() { let next = match self.lexer.next() {
Some(v) => v, Some(v) => v,
@ -236,7 +235,7 @@ impl<'a> StyleSheetParser<'a> {
q @ '"' | q @ '\'' => { q @ '"' | q @ '\'' => {
file_name.push_str( file_name.push_str(
&parse_quoted_string( &parse_quoted_string(
&mut self.lexer, self.lexer,
&Scope::new(), &Scope::new(),
q, q,
&Selector::new())? &Selector::new())?
@ -250,7 +249,7 @@ impl<'a> StyleSheetParser<'a> {
} }
} }
devour_whitespace(&mut self.lexer); devour_whitespace(self.lexer);
let (new_rules, new_scope) = import(self.path, file_name.as_ref(), &mut self.map)?; let (new_rules, new_scope) = import(self.path, file_name.as_ref(), &mut self.map)?;
rules.extend(new_rules); rules.extend(new_rules);
@ -259,7 +258,7 @@ impl<'a> StyleSheetParser<'a> {
}); });
} }
v => { v => {
let rule = AtRule::from_tokens(v, span, &mut self.lexer, &mut Scope::new(), &Selector::new(), None)?; let rule = AtRule::from_tokens(v, span, self.lexer, &mut Scope::new(), &Selector::new(), None)?;
match rule.node { match rule.node {
AtRule::Mixin(name, mixin) => { AtRule::Mixin(name, mixin) => {
insert_global_mixin(&name, *mixin); insert_global_mixin(&name, *mixin);
@ -320,7 +319,7 @@ impl<'a> StyleSheetParser<'a> {
scope: &mut Scope, scope: &mut Scope,
) -> SassResult<Vec<Spanned<Stmt>>> { ) -> SassResult<Vec<Spanned<Stmt>>> {
let mut stmts = Vec::new(); let mut stmts = Vec::new();
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector, None)? { while let Some(expr) = eat_expr(self.lexer, scope, super_selector, None)? {
let span = expr.span; let span = expr.span;
match expr.node { match expr.node {
Expr::Style(s) => stmts.push(Spanned { Expr::Style(s) => stmts.push(Spanned {

View File

@ -161,6 +161,7 @@ pub(crate) fn peek_ident_no_interpolation<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
unit: bool, unit: bool,
) -> SassResult<Spanned<String>> { ) -> SassResult<Spanned<String>> {
// todo: panics on "$"
let mut span = toks.peek().unwrap().pos(); let mut span = toks.peek().unwrap().pos();
let mut text = String::new(); let mut text = String::new();
if toks.peek().unwrap().kind == '-' { if toks.peek().unwrap().kind == '-' {

View File

@ -123,3 +123,4 @@ error!(
"#{", "Error: expected \"}\"." "#{", "Error: expected \"}\"."
); );
error!(toplevel_hash, "#", "Error: expected \"{\"."); error!(toplevel_hash, "#", "Error: expected \"{\".");
error!(toplevel_var_no_colon, "$r", "Error: expected \":\".");