Initial implementation of @debug and @warn

This commit is contained in:
ConnorSkees 2020-01-11 20:41:36 -05:00
parent 42d0fa657f
commit fd423ce300
3 changed files with 112 additions and 36 deletions

View File

@ -314,7 +314,6 @@ impl fmt::UpperHex for Color {
} }
} }
impl Display for Color { impl Display for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:X}", self) write!(f, "{:X}", self)
@ -477,4 +476,4 @@ impl TryFrom<&str> for Color {
_ => Err("invalid color"), _ => Err("invalid color"),
} }
} }
} }

View File

@ -321,7 +321,11 @@ impl<'a> Lexer<'a> {
.next() .next()
.expect("this is impossible because we have already peeked"); .expect("this is impossible because we have already peeked");
self.pos.next_char(); self.pos.next_char();
name.push(tok); if tok == '_' {
name.push('-');
} else {
name.push(tok);
}
} }
TokenKind::Variable(name) TokenKind::Variable(name)
} }
@ -338,7 +342,11 @@ impl<'a> Lexer<'a> {
.next() .next()
.expect("this is impossible because we have already peeked"); .expect("this is impossible because we have already peeked");
self.pos.next_char(); self.pos.next_char();
string.push(tok); if tok == '_' {
string.push('-');
} else {
string.push(tok);
}
} }
if let Ok(kw) = Keyword::try_from(string.as_ref()) { if let Ok(kw) = Keyword::try_from(string.as_ref()) {

View File

@ -25,6 +25,7 @@
clippy::let_underscore_must_use, clippy::let_underscore_must_use,
clippy::module_name_repetitions clippy::module_name_repetitions
)] )]
// todo! handle erroring on styles at the toplevel
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::fs; use std::fs;
@ -205,7 +206,7 @@ impl<'a> StyleSheetParser<'a> {
| TokenKind::Symbol(Symbol::Period) => rules.extend( | TokenKind::Symbol(Symbol::Period) => rules.extend(
self.eat_rules(&Selector(Vec::new()), &mut self.global_variables.clone()), self.eat_rules(&Selector(Vec::new()), &mut self.global_variables.clone()),
), ),
TokenKind::Whitespace(_) | TokenKind::Symbol(_) => { TokenKind::Whitespace(_) => {
self.lexer.next(); self.lexer.next();
continue; continue;
} }
@ -232,7 +233,13 @@ impl<'a> StyleSheetParser<'a> {
rules.push(Stmt::MultilineComment(comment)); rules.push(Stmt::MultilineComment(comment));
} }
TokenKind::AtRule(_) => self.eat_at_rule(), TokenKind::AtRule(_) => self.eat_at_rule(),
_ => todo!("unexpected toplevel token"), _ => {
if let Some(Token { pos, .. }) = self.lexer.next() {
self.error(pos.clone(), "unexpected toplevel token")
} else {
unsafe { std::hint::unreachable_unchecked() }
}
},
}; };
} }
Ok(StyleSheet { rules }) Ok(StyleSheet { rules })
@ -255,36 +262,31 @@ impl<'a> StyleSheetParser<'a> {
.collect::<String>(); .collect::<String>();
self.error(pos, &message); self.error(pos, &message);
} }
AtRule::Warn => {
self.devour_whitespace();
let message = self
.lexer
.by_ref()
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
self.warn(pos, &message);
}
AtRule::Debug => {
self.devour_whitespace();
let message = self
.lexer
.by_ref()
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
self.debug(pos, &message);
}
_ => todo!("encountered unimplemented at rule"), _ => todo!("encountered unimplemented at rule"),
} }
} }
} }
fn error(&self, pos: Pos, message: &str) -> ! {
eprintln!("Error: {}", message);
eprintln!(
"{} {}:{} scope on line {} at column {}",
self.file,
pos.line(),
pos.column(),
pos.line(),
pos.column()
);
let padding = vec![' '; format!("{}", pos.line()).len() + 1]
.iter()
.collect::<String>();
eprintln!("{}|", padding);
eprint!("{} | ", pos.line());
eprintln!("todo! get line to print as error");
eprintln!(
"{}| {}^",
padding,
vec![' '; pos.column() as usize].iter().collect::<String>()
);
eprintln!("{}|", padding);
std::process::exit(1);
}
fn eat_variable_value(&mut self) -> Vec<Token> { fn eat_variable_value(&mut self) -> Vec<Token> {
self.devour_whitespace(); self.devour_whitespace();
let iter1 = self let iter1 = self
@ -312,6 +314,10 @@ impl<'a> StyleSheetParser<'a> {
iter2 iter2
} }
fn eat_func_call(&mut self) {
}
fn eat_rules( fn eat_rules(
&mut self, &mut self,
super_selector: &Selector, super_selector: &Selector,
@ -354,20 +360,28 @@ impl<'a> StyleSheetParser<'a> {
super_selector: &Selector, super_selector: &Selector,
) -> Result<Expr, ()> { ) -> Result<Expr, ()> {
let mut values = Vec::with_capacity(5); let mut values = Vec::with_capacity(5);
while let Some(tok) = self.lexer.next() { while let Some(tok) = self.lexer.peek() {
match tok.kind { match &tok.kind {
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseBrace) => { TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseBrace) => {
self.lexer.next();
self.devour_whitespace(); self.devour_whitespace();
return Ok(Expr::Style(Style::from_tokens(&values, vars)?)); return Ok(Expr::Style(Style::from_tokens(&values, vars)?));
} }
TokenKind::Symbol(Symbol::OpenBrace) => { TokenKind::Symbol(Symbol::OpenBrace) => {
self.lexer.next();
self.devour_whitespace(); self.devour_whitespace();
return Ok(Expr::Selector(Selector::from_tokens( return Ok(Expr::Selector(Selector::from_tokens(
values.iter().peekable(), values.iter().peekable(),
super_selector, super_selector,
))); )));
} }
TokenKind::Variable(name) => { TokenKind::Variable(_) => {
let tok = self.lexer.next().unwrap();
let name = if let TokenKind::Variable(n) = tok.kind {
n
} else {
unsafe { std::hint::unreachable_unchecked() }
};
if let TokenKind::Symbol(Symbol::Colon) = self if let TokenKind::Symbol(Symbol::Colon) = self
.lexer .lexer
.peek() .peek()
@ -384,7 +398,13 @@ impl<'a> StyleSheetParser<'a> {
}); });
} }
} }
TokenKind::MultilineComment(ref s) => { TokenKind::MultilineComment(_) => {
let tok = self.lexer.next().unwrap();
let s = if let TokenKind::MultilineComment(s) = &tok.kind {
s
} else {
unsafe { std::hint::unreachable_unchecked() }
};
self.devour_whitespace(); self.devour_whitespace();
if values.is_empty() { if values.is_empty() {
return Ok(Expr::MultilineComment(s.clone())); return Ok(Expr::MultilineComment(s.clone()));
@ -392,7 +412,14 @@ impl<'a> StyleSheetParser<'a> {
values.push(tok.clone()) values.push(tok.clone())
} }
} }
_ => values.push(tok.clone()), TokenKind::AtRule(_) => self.eat_at_rule(),
_ => {
if let Some(tok) = self.lexer.next() {
values.push(tok.clone())
} else {
unsafe { std::hint::unreachable_unchecked() }
}
}
}; };
} }
Err(()) Err(())
@ -410,6 +437,48 @@ impl<'a> StyleSheetParser<'a> {
} }
} }
/// Functions that print to stdout or stderr
impl<'a> StyleSheetParser<'a> {
fn debug(&self, pos: Pos, message: &str) {
println!("{}:{} Debug: {}", self.file, pos.line(), message);
}
fn warn(&self, pos: Pos, message: &str) {
eprintln!(
"Warning: {}\n\t{} {}:{} todo!(scope)",
message,
self.file,
pos.line(),
pos.column()
);
}
fn error(&self, pos: Pos, message: &str) -> ! {
eprintln!("Error: {}", message);
eprintln!(
"{} {}:{} todo!(scope) on line {} at column {}",
self.file,
pos.line(),
pos.column(),
pos.line(),
pos.column()
);
let padding = vec![' '; format!("{}", pos.line()).len() + 1]
.iter()
.collect::<String>();
eprintln!("{}|", padding);
eprint!("{} | ", pos.line());
eprintln!("todo! get line to print as error");
eprintln!(
"{}| {}^",
padding,
vec![' '; pos.column() as usize].iter().collect::<String>()
);
eprintln!("{}|", padding);
std::process::exit(1);
}
}
fn main() -> SassResult<()> { fn main() -> SassResult<()> {
let mut stdout = std::io::stdout(); let mut stdout = std::io::stdout();
let s = StyleSheet::from_path("input.scss")?; let s = StyleSheet::from_path("input.scss")?;