initial parsing work for modules
This commit is contained in:
parent
dee6699bde
commit
3a7a3f508a
@ -80,7 +80,7 @@ grass input.scss
|
||||
)]
|
||||
#![cfg_attr(feature = "nightly", feature(track_caller))]
|
||||
#![cfg_attr(feature = "profiling", inline(never))]
|
||||
use std::{fs, path::Path};
|
||||
use std::{collections::HashMap, fs, path::Path};
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
@ -292,6 +292,7 @@ pub fn from_path(p: &str, options: &Options) -> Result<String> {
|
||||
extender: &mut Extender::new(empty_span),
|
||||
content_scopes: &mut Scopes::new(),
|
||||
options,
|
||||
modules: &mut HashMap::new(),
|
||||
}
|
||||
.parse()
|
||||
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
|
||||
@ -336,6 +337,7 @@ pub fn from_string(p: String, options: &Options) -> Result<String> {
|
||||
extender: &mut Extender::new(empty_span),
|
||||
content_scopes: &mut Scopes::new(),
|
||||
options,
|
||||
modules: &mut HashMap::new(),
|
||||
}
|
||||
.parse()
|
||||
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
|
||||
@ -371,6 +373,7 @@ pub fn from_string(p: String) -> std::result::Result<String, JsValue> {
|
||||
extender: &mut Extender::new(empty_span),
|
||||
content_scopes: &mut Scopes::new(),
|
||||
options: &Options::default(),
|
||||
modules: &mut HashMap::new(),
|
||||
}
|
||||
.parse()
|
||||
.map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?;
|
||||
|
@ -53,6 +53,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_stmt()?;
|
||||
} else {
|
||||
@ -112,6 +113,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_stmt()?;
|
||||
} else {
|
||||
@ -140,6 +142,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_stmt();
|
||||
}
|
||||
@ -320,8 +323,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?;
|
||||
.parse_stmt()?;
|
||||
if !these_stmts.is_empty() {
|
||||
return Ok(these_stmts);
|
||||
}
|
||||
@ -342,8 +346,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?,
|
||||
.parse_stmt()?,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -392,8 +397,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?;
|
||||
.parse_stmt()?;
|
||||
if !these_stmts.is_empty() {
|
||||
return Ok(these_stmts);
|
||||
}
|
||||
@ -414,8 +420,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?,
|
||||
.parse_stmt()?,
|
||||
);
|
||||
}
|
||||
val = self.parse_value_from_vec(cond.clone(), true)?;
|
||||
@ -517,8 +524,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?;
|
||||
.parse_stmt()?;
|
||||
if !these_stmts.is_empty() {
|
||||
return Ok(these_stmts);
|
||||
}
|
||||
@ -539,8 +547,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?,
|
||||
.parse_stmt()?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -108,8 +108,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?;
|
||||
.parse_stmt()?;
|
||||
|
||||
if entered_scope {
|
||||
self.scopes.exit_scope();
|
||||
|
@ -102,6 +102,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse();
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
})
|
||||
.parse_keyframes_selector()?;
|
||||
|
||||
@ -197,6 +198,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_stmt()?;
|
||||
|
||||
|
@ -155,8 +155,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?;
|
||||
.parse_stmt()?;
|
||||
|
||||
self.content.pop();
|
||||
self.scopes.exit_scope();
|
||||
@ -207,8 +208,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?
|
||||
.parse_stmt()?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{convert::TryFrom, path::Path, vec::IntoIter};
|
||||
use std::{collections::HashMap, convert::TryFrom, path::Path, vec::IntoIter};
|
||||
|
||||
use codemap::{CodeMap, Span, Spanned};
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
@ -86,11 +86,17 @@ pub(crate) struct Parser<'a> {
|
||||
pub extender: &'a mut Extender,
|
||||
|
||||
pub options: &'a Options<'a>,
|
||||
|
||||
pub modules: &'a mut HashMap<String, Scope>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn parse(&mut self) -> SassResult<Vec<Stmt>> {
|
||||
let mut stmts = Vec::new();
|
||||
|
||||
self.whitespace();
|
||||
stmts.append(&mut self.load_modules()?);
|
||||
|
||||
while self.toks.peek().is_some() {
|
||||
stmts.append(&mut self.parse_stmt()?);
|
||||
if self.flags.in_function() && !stmts.is_empty() {
|
||||
@ -101,6 +107,76 @@ impl<'a> Parser<'a> {
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
/// Returns any multiline comments that may have been found
|
||||
/// while loading modules
|
||||
fn load_modules(&mut self) -> SassResult<Vec<Stmt>> {
|
||||
let mut comments = Vec::new();
|
||||
|
||||
loop {
|
||||
self.whitespace();
|
||||
match self.toks.peek() {
|
||||
Some(Token { kind: '@', .. }) => {
|
||||
self.toks.advance_cursor();
|
||||
|
||||
match AtRuleKind::try_from(&peek_ident_no_interpolation(
|
||||
self.toks,
|
||||
false,
|
||||
self.span_before,
|
||||
)?)? {
|
||||
AtRuleKind::Use => {
|
||||
self.toks.truncate_iterator_to_cursor();
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.whitespace_or_comment();
|
||||
|
||||
let quote = match self.toks.next() {
|
||||
Some(Token { kind: q @ '"', .. }) | Some(Token { kind: q @ '\'', .. }) => q,
|
||||
Some(..) => todo!(),
|
||||
None => todo!(),
|
||||
};
|
||||
|
||||
let Spanned { node: module, span } = self.parse_quoted_string(quote)?;
|
||||
let module = module.unquote().to_css_string(span)?;
|
||||
|
||||
if let Some(Token { kind: ';', .. }) = self.toks.peek() {
|
||||
self.toks.next();
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
||||
match module.as_ref() {
|
||||
"sass:color" => todo!("builtin module `sass:color` not yet implemented"),
|
||||
"sass:list" => todo!("builtin module `sass:list` not yet implemented"),
|
||||
"sass:map" => todo!("builtin module `sass:map` not yet implemented"),
|
||||
"sass:math" => todo!("builtin module `sass:math` not yet implemented"),
|
||||
"sass:meta" => todo!("builtin module `sass:meta` not yet implemented"),
|
||||
"sass:selector" => {
|
||||
todo!("builtin module `sass:selector` not yet implemented")
|
||||
}
|
||||
"sass:string" => todo!("builtin module `sass:string` not yet implemented"),
|
||||
_ => todo!("@use not yet implemented"),
|
||||
}
|
||||
}
|
||||
Some(Token { kind: '/', .. }) => {
|
||||
self.toks.advance_cursor();
|
||||
match self.parse_comment()?.node {
|
||||
Comment::Silent => continue,
|
||||
Comment::Loud(s) => comments.push(Stmt::Comment(s)),
|
||||
}
|
||||
}
|
||||
Some(..) | None => break,
|
||||
}
|
||||
}
|
||||
|
||||
self.toks.reset_cursor();
|
||||
|
||||
Ok(comments)
|
||||
}
|
||||
|
||||
fn parse_stmt(&mut self) -> SassResult<Vec<Stmt>> {
|
||||
let mut stmts = Vec::new();
|
||||
while let Some(Token { kind, pos }) = self.toks.peek() {
|
||||
@ -196,7 +272,13 @@ impl<'a> Parser<'a> {
|
||||
AtRuleKind::Unknown(_) => {
|
||||
stmts.push(self.parse_unknown_at_rule(kind_string.node)?)
|
||||
}
|
||||
AtRuleKind::Use => todo!("@use not yet implemented"),
|
||||
AtRuleKind::Use => {
|
||||
return Err((
|
||||
"@use rules must be written before any other rules.",
|
||||
kind_string.span,
|
||||
)
|
||||
.into())
|
||||
}
|
||||
AtRuleKind::Forward => todo!("@forward not yet implemented"),
|
||||
AtRuleKind::Extend => self.parse_extend()?,
|
||||
AtRuleKind::Supports => stmts.push(self.parse_supports()?),
|
||||
@ -377,6 +459,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
},
|
||||
allows_parent,
|
||||
true,
|
||||
@ -668,8 +751,9 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse()?
|
||||
.parse_stmt()?
|
||||
.into_iter()
|
||||
.filter_map(|s| match s {
|
||||
Stmt::Style(..) => {
|
||||
@ -709,6 +793,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_selector(false, true, String::new())?;
|
||||
|
||||
|
@ -202,6 +202,7 @@ impl<'a> Parser<'a> {
|
||||
extender: self.extender,
|
||||
content_scopes: self.content_scopes,
|
||||
options: self.options,
|
||||
modules: self.modules,
|
||||
}
|
||||
.parse_value(in_paren)
|
||||
}
|
||||
|
@ -477,6 +477,7 @@ impl Value {
|
||||
extender: parser.extender,
|
||||
content_scopes: parser.content_scopes,
|
||||
options: parser.options,
|
||||
modules: parser.modules,
|
||||
}
|
||||
.parse_selector(allows_parent, true, String::new())?
|
||||
.0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user