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 = "nightly", feature(track_caller))]
|
||||||
#![cfg_attr(feature = "profiling", inline(never))]
|
#![cfg_attr(feature = "profiling", inline(never))]
|
||||||
use std::{fs, path::Path};
|
use std::{collections::HashMap, fs, path::Path};
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
@ -292,6 +292,7 @@ pub fn from_path(p: &str, options: &Options) -> Result<String> {
|
|||||||
extender: &mut Extender::new(empty_span),
|
extender: &mut Extender::new(empty_span),
|
||||||
content_scopes: &mut Scopes::new(),
|
content_scopes: &mut Scopes::new(),
|
||||||
options,
|
options,
|
||||||
|
modules: &mut HashMap::new(),
|
||||||
}
|
}
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
|
.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),
|
extender: &mut Extender::new(empty_span),
|
||||||
content_scopes: &mut Scopes::new(),
|
content_scopes: &mut Scopes::new(),
|
||||||
options,
|
options,
|
||||||
|
modules: &mut HashMap::new(),
|
||||||
}
|
}
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e, options.unicode_error_messages))?;
|
.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),
|
extender: &mut Extender::new(empty_span),
|
||||||
content_scopes: &mut Scopes::new(),
|
content_scopes: &mut Scopes::new(),
|
||||||
options: &Options::default(),
|
options: &Options::default(),
|
||||||
|
modules: &mut HashMap::new(),
|
||||||
}
|
}
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?;
|
.map_err(|e| raw_to_parse_error(&map, *e, true).to_string())?;
|
||||||
|
@ -53,6 +53,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_stmt()?;
|
.parse_stmt()?;
|
||||||
} else {
|
} else {
|
||||||
@ -112,6 +113,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_stmt()?;
|
.parse_stmt()?;
|
||||||
} else {
|
} else {
|
||||||
@ -140,6 +142,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_stmt();
|
.parse_stmt();
|
||||||
}
|
}
|
||||||
@ -320,8 +323,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse_stmt()?;
|
||||||
if !these_stmts.is_empty() {
|
if !these_stmts.is_empty() {
|
||||||
return Ok(these_stmts);
|
return Ok(these_stmts);
|
||||||
}
|
}
|
||||||
@ -342,8 +346,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?,
|
.parse_stmt()?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,8 +397,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse_stmt()?;
|
||||||
if !these_stmts.is_empty() {
|
if !these_stmts.is_empty() {
|
||||||
return Ok(these_stmts);
|
return Ok(these_stmts);
|
||||||
}
|
}
|
||||||
@ -414,8 +420,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?,
|
.parse_stmt()?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
val = self.parse_value_from_vec(cond.clone(), true)?;
|
val = self.parse_value_from_vec(cond.clone(), true)?;
|
||||||
@ -517,8 +524,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse_stmt()?;
|
||||||
if !these_stmts.is_empty() {
|
if !these_stmts.is_empty() {
|
||||||
return Ok(these_stmts);
|
return Ok(these_stmts);
|
||||||
}
|
}
|
||||||
@ -539,8 +547,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?,
|
.parse_stmt()?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,8 +108,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse_stmt()?;
|
||||||
|
|
||||||
if entered_scope {
|
if entered_scope {
|
||||||
self.scopes.exit_scope();
|
self.scopes.exit_scope();
|
||||||
|
@ -102,6 +102,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse();
|
.parse();
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
})
|
})
|
||||||
.parse_keyframes_selector()?;
|
.parse_keyframes_selector()?;
|
||||||
|
|
||||||
@ -197,6 +198,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_stmt()?;
|
.parse_stmt()?;
|
||||||
|
|
||||||
|
@ -155,8 +155,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse_stmt()?;
|
||||||
|
|
||||||
self.content.pop();
|
self.content.pop();
|
||||||
self.scopes.exit_scope();
|
self.scopes.exit_scope();
|
||||||
@ -207,8 +208,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.scopes,
|
content_scopes: self.scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?
|
.parse_stmt()?
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
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 codemap::{CodeMap, Span, Spanned};
|
||||||
use peekmore::{PeekMore, PeekMoreIterator};
|
use peekmore::{PeekMore, PeekMoreIterator};
|
||||||
@ -86,11 +86,17 @@ pub(crate) struct Parser<'a> {
|
|||||||
pub extender: &'a mut Extender,
|
pub extender: &'a mut Extender,
|
||||||
|
|
||||||
pub options: &'a Options<'a>,
|
pub options: &'a Options<'a>,
|
||||||
|
|
||||||
|
pub modules: &'a mut HashMap<String, Scope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub fn parse(&mut self) -> SassResult<Vec<Stmt>> {
|
pub fn parse(&mut self) -> SassResult<Vec<Stmt>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
|
|
||||||
|
self.whitespace();
|
||||||
|
stmts.append(&mut self.load_modules()?);
|
||||||
|
|
||||||
while self.toks.peek().is_some() {
|
while self.toks.peek().is_some() {
|
||||||
stmts.append(&mut self.parse_stmt()?);
|
stmts.append(&mut self.parse_stmt()?);
|
||||||
if self.flags.in_function() && !stmts.is_empty() {
|
if self.flags.in_function() && !stmts.is_empty() {
|
||||||
@ -101,6 +107,76 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(stmts)
|
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>> {
|
fn parse_stmt(&mut self) -> SassResult<Vec<Stmt>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(Token { kind, pos }) = self.toks.peek() {
|
while let Some(Token { kind, pos }) = self.toks.peek() {
|
||||||
@ -196,7 +272,13 @@ impl<'a> Parser<'a> {
|
|||||||
AtRuleKind::Unknown(_) => {
|
AtRuleKind::Unknown(_) => {
|
||||||
stmts.push(self.parse_unknown_at_rule(kind_string.node)?)
|
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::Forward => todo!("@forward not yet implemented"),
|
||||||
AtRuleKind::Extend => self.parse_extend()?,
|
AtRuleKind::Extend => self.parse_extend()?,
|
||||||
AtRuleKind::Supports => stmts.push(self.parse_supports()?),
|
AtRuleKind::Supports => stmts.push(self.parse_supports()?),
|
||||||
@ -377,6 +459,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
},
|
},
|
||||||
allows_parent,
|
allows_parent,
|
||||||
true,
|
true,
|
||||||
@ -668,8 +751,9 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse()?
|
.parse_stmt()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|s| match s {
|
.filter_map(|s| match s {
|
||||||
Stmt::Style(..) => {
|
Stmt::Style(..) => {
|
||||||
@ -709,6 +793,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_selector(false, true, String::new())?;
|
.parse_selector(false, true, String::new())?;
|
||||||
|
|
||||||
|
@ -202,6 +202,7 @@ impl<'a> Parser<'a> {
|
|||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
content_scopes: self.content_scopes,
|
content_scopes: self.content_scopes,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
|
modules: self.modules,
|
||||||
}
|
}
|
||||||
.parse_value(in_paren)
|
.parse_value(in_paren)
|
||||||
}
|
}
|
||||||
|
@ -477,6 +477,7 @@ impl Value {
|
|||||||
extender: parser.extender,
|
extender: parser.extender,
|
||||||
content_scopes: parser.content_scopes,
|
content_scopes: parser.content_scopes,
|
||||||
options: parser.options,
|
options: parser.options,
|
||||||
|
modules: parser.modules,
|
||||||
}
|
}
|
||||||
.parse_selector(allows_parent, true, String::new())?
|
.parse_selector(allows_parent, true, String::new())?
|
||||||
.0)
|
.0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user