lex: separate escaped/non-escaped
This commit is contained in:
parent
e877fdbde8
commit
3701d282ac
1 changed files with 102 additions and 106 deletions
208
src/lex.rs
208
src/lex.rs
|
@ -93,7 +93,7 @@ impl<'s> Lexer<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: Peeked [`Kind::Text`] tokens are only one char long, they may be longer when
|
/// NOTE: Peeked [`Kind::Text`] tokens are only one byte long, they may be longer when
|
||||||
/// consumed.
|
/// consumed.
|
||||||
pub fn peek(&mut self) -> Option<&Token> {
|
pub fn peek(&mut self) -> Option<&Token> {
|
||||||
if self.next.is_none() {
|
if self.next.is_none() {
|
||||||
|
@ -150,112 +150,108 @@ impl<'s> Lexer<'s> {
|
||||||
fn token(&mut self) -> Option<Token> {
|
fn token(&mut self) -> Option<Token> {
|
||||||
self.len = 0;
|
self.len = 0;
|
||||||
|
|
||||||
let first = self.eat_char()?;
|
let kind = if self.escape {
|
||||||
|
|
||||||
let escape = self.escape;
|
|
||||||
|
|
||||||
let kind = match first {
|
|
||||||
_ if escape && first == '\n' => Hardbreak,
|
|
||||||
_ if escape
|
|
||||||
&& matches!(first, '\t' | ' ')
|
|
||||||
&& self.chars.clone().find(|c| !matches!(c, ' ' | '\t')) == Some('\n') =>
|
|
||||||
{
|
|
||||||
while self.eat_char() != Some('\n') {}
|
|
||||||
Hardbreak
|
|
||||||
}
|
|
||||||
_ if escape && first == ' ' => Nbsp,
|
|
||||||
_ if escape => Text,
|
|
||||||
|
|
||||||
'\n' => Newline,
|
|
||||||
|
|
||||||
'\\' => {
|
|
||||||
if self
|
|
||||||
.peek_char()
|
|
||||||
.map_or(false, |c| c.is_whitespace() || c.is_ascii_punctuation())
|
|
||||||
{
|
|
||||||
self.escape = true;
|
|
||||||
Escape
|
|
||||||
} else {
|
|
||||||
Text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'[' => Open(Bracket),
|
|
||||||
']' => Close(Bracket),
|
|
||||||
'(' => Open(Paren),
|
|
||||||
')' => Close(Paren),
|
|
||||||
'{' => {
|
|
||||||
let explicit = match self.peek_char() {
|
|
||||||
Some('*') => Some(Open(BraceAsterisk)),
|
|
||||||
Some('^') => Some(Open(BraceCaret)),
|
|
||||||
Some('=') => Some(Open(BraceEqual)),
|
|
||||||
Some('-') => Some(Open(BraceHyphen)),
|
|
||||||
Some('+') => Some(Open(BracePlus)),
|
|
||||||
Some('~') => Some(Open(BraceTilde)),
|
|
||||||
Some('_') => Some(Open(BraceUnderscore)),
|
|
||||||
Some('\'') => Some(Open(BraceQuote1)),
|
|
||||||
Some('"') => Some(Open(BraceQuote2)),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if let Some(exp) = explicit {
|
|
||||||
self.eat_char();
|
|
||||||
exp
|
|
||||||
} else {
|
|
||||||
Open(Brace)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'}' => Close(Brace),
|
|
||||||
'*' => self.maybe_eat_close_brace(Sym(Asterisk), BraceAsterisk),
|
|
||||||
'^' => self.maybe_eat_close_brace(Sym(Caret), BraceCaret),
|
|
||||||
'=' => self.maybe_eat_close_brace(Text, BraceEqual),
|
|
||||||
'+' => self.maybe_eat_close_brace(Text, BracePlus),
|
|
||||||
'~' => self.maybe_eat_close_brace(Sym(Tilde), BraceTilde),
|
|
||||||
'_' => self.maybe_eat_close_brace(Sym(Underscore), BraceUnderscore),
|
|
||||||
'\'' => self.maybe_eat_close_brace(Sym(Quote1), BraceQuote1),
|
|
||||||
'"' => self.maybe_eat_close_brace(Sym(Quote2), BraceQuote2),
|
|
||||||
'-' => {
|
|
||||||
if self.peek_char() == Some('}') {
|
|
||||||
self.eat_char();
|
|
||||||
Close(BraceHyphen)
|
|
||||||
} else {
|
|
||||||
while self.peek_char() == Some('-') && self.peek_char_n(1) != Some('}') {
|
|
||||||
self.eat_char();
|
|
||||||
}
|
|
||||||
Seq(Hyphen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'!' if self.peek_char() == Some('[') => {
|
|
||||||
self.eat_char();
|
|
||||||
Sym(ExclaimBracket)
|
|
||||||
}
|
|
||||||
'<' => Sym(Lt),
|
|
||||||
'|' => Sym(Pipe),
|
|
||||||
':' => Sym(Colon),
|
|
||||||
|
|
||||||
'`' => self.eat_seq(Backtick),
|
|
||||||
'.' => self.eat_seq(Period),
|
|
||||||
'$' => {
|
|
||||||
self.eat_while(|c| c == '$');
|
|
||||||
let mut n_ticks: u8 = 0;
|
|
||||||
self.eat_while(|c| {
|
|
||||||
if c == '`' {
|
|
||||||
if let Some(l) = n_ticks.checked_add(1) {
|
|
||||||
n_ticks = l;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
});
|
|
||||||
DollarBacktick(n_ticks)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Text,
|
|
||||||
};
|
|
||||||
|
|
||||||
if escape {
|
|
||||||
self.escape = false;
|
self.escape = false;
|
||||||
}
|
match self.eat_char()? {
|
||||||
|
'\n' => Hardbreak,
|
||||||
|
'\t' | ' '
|
||||||
|
if self.chars.clone().find(|c| !matches!(c, ' ' | '\t')) == Some('\n') =>
|
||||||
|
{
|
||||||
|
while self.eat_char() != Some('\n') {}
|
||||||
|
Hardbreak
|
||||||
|
}
|
||||||
|
' ' => Nbsp,
|
||||||
|
_ => Text,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.eat_char()? {
|
||||||
|
'\n' => Newline,
|
||||||
|
|
||||||
|
'\\' => {
|
||||||
|
if self
|
||||||
|
.peek_char()
|
||||||
|
.map_or(false, |c| c.is_whitespace() || c.is_ascii_punctuation())
|
||||||
|
{
|
||||||
|
self.escape = true;
|
||||||
|
Escape
|
||||||
|
} else {
|
||||||
|
Text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'[' => Open(Bracket),
|
||||||
|
']' => Close(Bracket),
|
||||||
|
'(' => Open(Paren),
|
||||||
|
')' => Close(Paren),
|
||||||
|
'{' => {
|
||||||
|
let explicit = match self.peek_char() {
|
||||||
|
Some('*') => Some(Open(BraceAsterisk)),
|
||||||
|
Some('^') => Some(Open(BraceCaret)),
|
||||||
|
Some('=') => Some(Open(BraceEqual)),
|
||||||
|
Some('-') => Some(Open(BraceHyphen)),
|
||||||
|
Some('+') => Some(Open(BracePlus)),
|
||||||
|
Some('~') => Some(Open(BraceTilde)),
|
||||||
|
Some('_') => Some(Open(BraceUnderscore)),
|
||||||
|
Some('\'') => Some(Open(BraceQuote1)),
|
||||||
|
Some('"') => Some(Open(BraceQuote2)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(exp) = explicit {
|
||||||
|
self.eat_char();
|
||||||
|
exp
|
||||||
|
} else {
|
||||||
|
Open(Brace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'}' => Close(Brace),
|
||||||
|
'*' => self.maybe_eat_close_brace(Sym(Asterisk), BraceAsterisk),
|
||||||
|
'^' => self.maybe_eat_close_brace(Sym(Caret), BraceCaret),
|
||||||
|
'=' => self.maybe_eat_close_brace(Text, BraceEqual),
|
||||||
|
'+' => self.maybe_eat_close_brace(Text, BracePlus),
|
||||||
|
'~' => self.maybe_eat_close_brace(Sym(Tilde), BraceTilde),
|
||||||
|
'_' => self.maybe_eat_close_brace(Sym(Underscore), BraceUnderscore),
|
||||||
|
'\'' => self.maybe_eat_close_brace(Sym(Quote1), BraceQuote1),
|
||||||
|
'"' => self.maybe_eat_close_brace(Sym(Quote2), BraceQuote2),
|
||||||
|
'-' => {
|
||||||
|
if self.peek_char() == Some('}') {
|
||||||
|
self.eat_char();
|
||||||
|
Close(BraceHyphen)
|
||||||
|
} else {
|
||||||
|
while self.peek_char() == Some('-') && self.peek_char_n(1) != Some('}') {
|
||||||
|
self.eat_char();
|
||||||
|
}
|
||||||
|
Seq(Hyphen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'!' if self.peek_char() == Some('[') => {
|
||||||
|
self.eat_char();
|
||||||
|
Sym(ExclaimBracket)
|
||||||
|
}
|
||||||
|
'<' => Sym(Lt),
|
||||||
|
'|' => Sym(Pipe),
|
||||||
|
':' => Sym(Colon),
|
||||||
|
|
||||||
|
'`' => self.eat_seq(Backtick),
|
||||||
|
'.' => self.eat_seq(Period),
|
||||||
|
'$' => {
|
||||||
|
self.eat_while(|c| c == '$');
|
||||||
|
let mut n_ticks: u8 = 0;
|
||||||
|
self.eat_while(|c| {
|
||||||
|
if c == '`' {
|
||||||
|
if let Some(l) = n_ticks.checked_add(1) {
|
||||||
|
n_ticks = l;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
});
|
||||||
|
DollarBacktick(n_ticks)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Text,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Some(Token {
|
Some(Token {
|
||||||
kind,
|
kind,
|
||||||
|
|
Loading…
Reference in a new issue