// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+use std::convert::TryFrom;
use std::fmt;
use std::str::{CharIndices, FromStr};
-pub trait MyTryFrom<T>: Sized {
- type Error;
- fn try_from(value: T) -> Result<Self, Self::Error>;
-}
-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub enum ReservedChar {
Comma,
SuperiorThan,
Pipe,
Ampersand,
+ BackTick,
}
impl ReservedChar {
pub fn is_white_character(&self) -> bool {
- *self == ReservedChar::Space ||
- *self == ReservedChar::Tab ||
- *self == ReservedChar::Backline
+ *self == ReservedChar::Space
+ || *self == ReservedChar::Tab
+ || *self == ReservedChar::Backline
}
}
impl fmt::Display for ReservedChar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}",
- match *self {
- ReservedChar::Comma => ',',
- ReservedChar::OpenParenthese => '(',
- ReservedChar::CloseParenthese => ')',
- ReservedChar::OpenCurlyBrace => '{',
- ReservedChar::CloseCurlyBrace => '}',
- ReservedChar::OpenBracket => '[',
- ReservedChar::CloseBracket => ']',
- ReservedChar::Colon => ':',
- ReservedChar::SemiColon => ';',
- ReservedChar::Dot => '.',
- ReservedChar::Quote => '\'',
- ReservedChar::DoubleQuote => '"',
- ReservedChar::ExclamationMark => '!',
- ReservedChar::QuestionMark => '?',
- ReservedChar::Slash => '/',
- ReservedChar::Modulo => '%',
- ReservedChar::Star => '*',
- ReservedChar::Minus => '-',
- ReservedChar::Plus => '+',
- ReservedChar::EqualSign => '=',
- ReservedChar::Backslash => '\\',
- ReservedChar::Space => ' ',
- ReservedChar::Tab => '\t',
- ReservedChar::Backline => '\n',
- ReservedChar::LessThan => '<',
- ReservedChar::SuperiorThan => '>',
- ReservedChar::Pipe => '|',
- ReservedChar::Ampersand => '&',
- })
+ write!(
+ f,
+ "{}",
+ match *self {
+ ReservedChar::Comma => ',',
+ ReservedChar::OpenParenthese => '(',
+ ReservedChar::CloseParenthese => ')',
+ ReservedChar::OpenCurlyBrace => '{',
+ ReservedChar::CloseCurlyBrace => '}',
+ ReservedChar::OpenBracket => '[',
+ ReservedChar::CloseBracket => ']',
+ ReservedChar::Colon => ':',
+ ReservedChar::SemiColon => ';',
+ ReservedChar::Dot => '.',
+ ReservedChar::Quote => '\'',
+ ReservedChar::DoubleQuote => '"',
+ ReservedChar::ExclamationMark => '!',
+ ReservedChar::QuestionMark => '?',
+ ReservedChar::Slash => '/',
+ ReservedChar::Modulo => '%',
+ ReservedChar::Star => '*',
+ ReservedChar::Minus => '-',
+ ReservedChar::Plus => '+',
+ ReservedChar::EqualSign => '=',
+ ReservedChar::Backslash => '\\',
+ ReservedChar::Space => ' ',
+ ReservedChar::Tab => '\t',
+ ReservedChar::Backline => '\n',
+ ReservedChar::LessThan => '<',
+ ReservedChar::SuperiorThan => '>',
+ ReservedChar::Pipe => '|',
+ ReservedChar::Ampersand => '&',
+ ReservedChar::BackTick => '`',
+ }
+ )
}
}
-impl MyTryFrom<char> for ReservedChar {
+impl TryFrom<char> for ReservedChar {
type Error = &'static str;
fn try_from(value: char) -> Result<ReservedChar, Self::Error> {
match value {
- ',' => Ok(ReservedChar::Comma),
- '(' => Ok(ReservedChar::OpenParenthese),
- ')' => Ok(ReservedChar::CloseParenthese),
- '{' => Ok(ReservedChar::OpenCurlyBrace),
- '}' => Ok(ReservedChar::CloseCurlyBrace),
- '[' => Ok(ReservedChar::OpenBracket),
- ']' => Ok(ReservedChar::CloseBracket),
- ':' => Ok(ReservedChar::Colon),
- ';' => Ok(ReservedChar::SemiColon),
- '.' => Ok(ReservedChar::Dot),
+ ',' => Ok(ReservedChar::Comma),
+ '(' => Ok(ReservedChar::OpenParenthese),
+ ')' => Ok(ReservedChar::CloseParenthese),
+ '{' => Ok(ReservedChar::OpenCurlyBrace),
+ '}' => Ok(ReservedChar::CloseCurlyBrace),
+ '[' => Ok(ReservedChar::OpenBracket),
+ ']' => Ok(ReservedChar::CloseBracket),
+ ':' => Ok(ReservedChar::Colon),
+ ';' => Ok(ReservedChar::SemiColon),
+ '.' => Ok(ReservedChar::Dot),
'\'' => Ok(ReservedChar::Quote),
- '"' => Ok(ReservedChar::DoubleQuote),
- '!' => Ok(ReservedChar::ExclamationMark),
- '?' => Ok(ReservedChar::QuestionMark),
- '/' => Ok(ReservedChar::Slash),
- '%' => Ok(ReservedChar::Modulo),
- '*' => Ok(ReservedChar::Star),
- '-' => Ok(ReservedChar::Minus),
- '+' => Ok(ReservedChar::Plus),
- '=' => Ok(ReservedChar::EqualSign),
+ '"' => Ok(ReservedChar::DoubleQuote),
+ '!' => Ok(ReservedChar::ExclamationMark),
+ '?' => Ok(ReservedChar::QuestionMark),
+ '/' => Ok(ReservedChar::Slash),
+ '%' => Ok(ReservedChar::Modulo),
+ '*' => Ok(ReservedChar::Star),
+ '-' => Ok(ReservedChar::Minus),
+ '+' => Ok(ReservedChar::Plus),
+ '=' => Ok(ReservedChar::EqualSign),
'\\' => Ok(ReservedChar::Backslash),
- ' ' => Ok(ReservedChar::Space),
+ ' ' => Ok(ReservedChar::Space),
'\t' => Ok(ReservedChar::Tab),
- '\n' |
- '\r' => Ok(ReservedChar::Backline),
- '<' => Ok(ReservedChar::LessThan),
- '>' => Ok(ReservedChar::SuperiorThan),
- '|' => Ok(ReservedChar::Pipe),
- '&' => Ok(ReservedChar::Ampersand),
- _ => Err("Unknown reserved char"),
+ '\n' | '\r' => Ok(ReservedChar::Backline),
+ '<' => Ok(ReservedChar::LessThan),
+ '>' => Ok(ReservedChar::SuperiorThan),
+ '|' => Ok(ReservedChar::Pipe),
+ '&' => Ok(ReservedChar::Ampersand),
+ '`' => Ok(ReservedChar::BackTick),
+ _ => Err("Unknown reserved char"),
}
}
}
impl Keyword {
fn requires_before(&self) -> bool {
- match *self {
- Keyword::In | Keyword::InstanceOf => true,
- _ => false,
- }
+ matches!(*self, Keyword::In | Keyword::InstanceOf)
}
}
impl fmt::Display for Keyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}",
- match *self {
- Keyword::Break => "break",
- Keyword::Case => "case",
- Keyword::Catch => "catch",
- Keyword::Const => "const",
- Keyword::Continue => "continue",
- Keyword::Default => "default",
- Keyword::Do => "do",
- Keyword::Else => "else",
- Keyword::False => "false",
- Keyword::Finally => "finally",
- Keyword::Function => "function",
- Keyword::For => "for",
- Keyword::If => "if",
- Keyword::In => "in",
- Keyword::InstanceOf => "instanceof",
- Keyword::Let => "let",
- Keyword::New => "new",
- Keyword::Null => "null",
- Keyword::Private => "private",
- Keyword::Protected => "protected",
- Keyword::Public => "public",
- Keyword::Return => "return",
- Keyword::Switch => "switch",
- Keyword::This => "this",
- Keyword::Throw => "throw",
- Keyword::True => "true",
- Keyword::Try => "try",
- Keyword::Typeof => "typeof",
- Keyword::Static => "static",
- Keyword::Var => "var",
- Keyword::While => "while",
- })
+ write!(
+ f,
+ "{}",
+ match *self {
+ Keyword::Break => "break",
+ Keyword::Case => "case",
+ Keyword::Catch => "catch",
+ Keyword::Const => "const",
+ Keyword::Continue => "continue",
+ Keyword::Default => "default",
+ Keyword::Do => "do",
+ Keyword::Else => "else",
+ Keyword::False => "false",
+ Keyword::Finally => "finally",
+ Keyword::Function => "function",
+ Keyword::For => "for",
+ Keyword::If => "if",
+ Keyword::In => "in",
+ Keyword::InstanceOf => "instanceof",
+ Keyword::Let => "let",
+ Keyword::New => "new",
+ Keyword::Null => "null",
+ Keyword::Private => "private",
+ Keyword::Protected => "protected",
+ Keyword::Public => "public",
+ Keyword::Return => "return",
+ Keyword::Switch => "switch",
+ Keyword::This => "this",
+ Keyword::Throw => "throw",
+ Keyword::True => "true",
+ Keyword::Try => "try",
+ Keyword::Typeof => "typeof",
+ Keyword::Static => "static",
+ Keyword::Var => "var",
+ Keyword::While => "while",
+ }
+ )
}
}
-impl<'a> MyTryFrom<&'a str> for Keyword {
+impl<'a> TryFrom<&'a str> for Keyword {
type Error = &'static str;
fn try_from(value: &str) -> Result<Keyword, Self::Error> {
impl fmt::Display for Condition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}",
- match *self {
- Condition::And => "&&",
- Condition::Or => "||",
- Condition::DifferentThan => "!=",
- Condition::SuperDifferentThan => "!==",
- Condition::EqualTo => "==",
- Condition::SuperEqualTo => "===",
- Condition::SuperiorThan => ">",
- Condition::SuperiorOrEqualTo => ">=",
- Condition::InferiorThan => "<",
- Condition::InferiorOrEqualTo => "<=",
- })
+ write!(
+ f,
+ "{}",
+ match *self {
+ Condition::And => "&&",
+ Condition::Or => "||",
+ Condition::DifferentThan => "!=",
+ Condition::SuperDifferentThan => "!==",
+ Condition::EqualTo => "==",
+ Condition::SuperEqualTo => "===",
+ Condition::SuperiorThan => ">",
+ Condition::SuperiorOrEqualTo => ">=",
+ Condition::InferiorThan => "<",
+ Condition::InferiorOrEqualTo => "<=",
+ }
+ )
}
}
-impl MyTryFrom<ReservedChar> for Condition {
+impl TryFrom<ReservedChar> for Condition {
type Error = &'static str;
fn try_from(value: ReservedChar) -> Result<Condition, Self::Error> {
Equal,
}
+impl Operation {
+ pub fn is_assign(&self) -> bool {
+ matches!(
+ *self,
+ Operation::AdditionEqual
+ | Operation::SubtractEqual
+ | Operation::MultiplyEqual
+ | Operation::DivideEqual
+ | Operation::ModuloEqual
+ | Operation::Equal
+ )
+ }
+}
+
impl fmt::Display for Operation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}",
- match *self {
- Operation::Addition => "+",
- Operation::AdditionEqual => "+=",
- Operation::Subtract => "-",
- Operation::SubtractEqual => "-=",
- Operation::Multiply => "*",
- Operation::MultiplyEqual => "*=",
- Operation::Divide => "/",
- Operation::DivideEqual => "/=",
- Operation::Modulo => "%",
- Operation::ModuloEqual => "%=",
- Operation::Equal => "=",
- })
+ write!(
+ f,
+ "{}",
+ match *self {
+ Operation::Addition => "+",
+ Operation::AdditionEqual => "+=",
+ Operation::Subtract => "-",
+ Operation::SubtractEqual => "-=",
+ Operation::Multiply => "*",
+ Operation::MultiplyEqual => "*=",
+ Operation::Divide => "/",
+ Operation::DivideEqual => "/=",
+ Operation::Modulo => "%",
+ Operation::ModuloEqual => "%=",
+ Operation::Equal => "=",
+ }
+ )
}
}
-impl MyTryFrom<ReservedChar> for Operation {
+impl TryFrom<ReservedChar> for Operation {
type Error = &'static str;
fn try_from(value: ReservedChar) -> Result<Operation, Self::Error> {
match *self {
Token::Keyword(x) => write!(f, "{}", x),
Token::Char(x) => write!(f, "{}", x),
- Token::String(x) |
- Token::Comment(x) |
- Token::Other(x) => write!(f, "{}", x),
+ Token::String(x) | Token::Comment(x) | Token::Other(x) => write!(f, "{}", x),
Token::License(x) => write!(f, "/*!{}*/", x),
- Token::Regex { regex, is_global, is_interactive } => {
+ Token::Regex {
+ regex,
+ is_global,
+ is_interactive,
+ } => {
let x = write!(f, "/{}/", regex);
if is_global {
write!(f, "g")?;
impl<'a> Token<'a> {
pub fn is_comment(&self) -> bool {
- match *self {
- Token::Comment(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Comment(_))
}
pub fn is_license(&self) -> bool {
- match *self {
- Token::License(_) => true,
- _ => false,
- }
+ matches!(*self, Token::License(_))
}
pub fn is_reserved_char(&self) -> bool {
- match *self {
- Token::Char(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Char(_))
}
pub fn get_char(&self) -> Option<ReservedChar> {
}
pub fn is_operation(&self) -> bool {
- match *self {
- Token::Operation(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Operation(_))
}
pub fn eq_condition(&self, cond: Condition) -> bool {
}
pub fn is_condition(&self) -> bool {
- match *self {
- Token::Condition(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Condition(_))
}
pub fn is_other(&self) -> bool {
- match *self {
- Token::Other(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Other(_))
}
pub fn get_other(&self) -> Option<&str> {
}
pub fn is_keyword(&self) -> bool {
- match *self {
- Token::Keyword(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Keyword(_))
}
pub fn get_keyword(&self) -> Option<Keyword> {
}
pub fn is_string(&self) -> bool {
- match *self {
- Token::String(_) => true,
- _ => false,
- }
+ matches!(*self, Token::String(_))
}
pub fn get_string(&self) -> Option<&str> {
}
pub fn is_regex(&self) -> bool {
- match *self {
- Token::Regex { .. } => true,
- _ => false,
- }
+ matches!(*self, Token::Regex { .. })
}
pub fn is_created_var_decl(&self) -> bool {
- match *self {
- Token::CreatedVarDecl(_) => true,
- _ => false,
- }
+ matches!(*self, Token::CreatedVarDecl(_))
}
pub fn is_created_var(&self) -> bool {
- match *self {
- Token::CreatedVar(_) => true,
- _ => false,
- }
+ matches!(*self, Token::CreatedVar(_))
}
pub fn is_number(&self) -> bool {
- match *self {
- Token::Number(_) => true,
- _ => false,
- }
+ matches!(*self, Token::Number(_))
}
pub fn is_floating_number(&self) -> bool {
- match *self {
- Token::FloatingNumber(_) => true,
- _ => false,
- }
+ matches!(*self, Token::FloatingNumber(_))
}
fn get_required(&self) -> Option<char> {
match *self {
- Token::Keyword(_) |
- Token::Other(_) |
- Token::CreatedVarDecl(_) |
- Token::Number(_) |
- Token::FloatingNumber(_) => Some(' '),
+ Token::Keyword(_)
+ | Token::Other(_)
+ | Token::CreatedVarDecl(_)
+ | Token::Number(_)
+ | Token::FloatingNumber(_) => Some(' '),
_ => None,
}
}
}
}
-fn get_line_comment<'a>(source: &'a str, iterator: &mut MyPeekable<'_>,
- start_pos: &mut usize) -> Option<Token<'a>> {
+fn get_line_comment<'a>(
+ source: &'a str,
+ iterator: &mut MyPeekable<'_>,
+ start_pos: &mut usize,
+) -> Option<Token<'a>> {
*start_pos += 1;
- while let Some((pos, c)) = iterator.next() {
+ for (pos, c) in iterator {
if let Ok(c) = ReservedChar::try_from(c) {
if c == ReservedChar::Backline {
let ret = Some(Token::Comment(&source[*start_pos..pos]));
None
}
-fn get_regex<'a>(source: &'a str, iterator: &mut MyPeekable<'_>,
- start_pos: &mut usize, v: &[Token]) -> Option<Token<'a>> {
+fn get_regex<'a>(
+ source: &'a str,
+ iterator: &mut MyPeekable<'_>,
+ start_pos: &mut usize,
+ v: &[Token],
+) -> Option<Token<'a>> {
let mut back = v.len();
while back > 0 {
back -= 1;
if v[back].is_white_character() || v[back].is_comment() || v[back].is_license() {
- continue
+ continue;
}
match &v[back] {
- Token::Char(ReservedChar::SemiColon) |
- Token::Char(ReservedChar::Colon) |
- Token::Char(ReservedChar::Comma) |
- Token::Char(ReservedChar::OpenBracket) |
- Token::Char(ReservedChar::CloseBracket) |
- Token::Char(ReservedChar::OpenParenthese) |
- Token::Char(ReservedChar::CloseParenthese) => break,
- x if x.is_operation() || x.is_number() || x.is_floating_number() ||
- x.is_condition() || x.is_other() => break,
+ Token::Char(ReservedChar::SemiColon)
+ | Token::Char(ReservedChar::Colon)
+ | Token::Char(ReservedChar::Comma)
+ | Token::Char(ReservedChar::OpenBracket)
+ | Token::Char(ReservedChar::OpenParenthese)
+ | Token::Operation(Operation::Equal) => break,
_ => return None,
}
}
iterator.start_save();
- *start_pos += 1;
while let Some((pos, c)) = iterator.next() {
if c == '\\' {
// we skip next character
iterator.next();
- continue
+ continue;
}
if let Ok(c) = ReservedChar::try_from(c) {
if c == ReservedChar::Slash {
add += 1;
}
let ret = Some(Token::Regex {
- regex: &source[*start_pos..pos],
- is_interactive: is_interactive,
- is_global: is_global,
- });
+ regex: &source[*start_pos + 1..pos],
+ is_interactive,
+ is_global,
+ });
*start_pos = pos + add;
iterator.drop_save();
return ret;
- } else if c.is_white_character() {
+ } else if c == ReservedChar::Backline {
break;
}
}
None
}
-fn get_comment<'a>(source: &'a str, iterator: &mut MyPeekable<'_>,
- start_pos: &mut usize) -> Option<Token<'a>> {
+fn get_comment<'a>(
+ source: &'a str,
+ iterator: &mut MyPeekable<'_>,
+ start_pos: &mut usize,
+) -> Option<Token<'a>> {
let mut prev = ReservedChar::Quote;
*start_pos += 1;
let builder = if let Some((_, c)) = iterator.next() {
Token::Comment
};
- while let Some((pos, c)) = iterator.next() {
+ for (pos, c) in iterator {
if let Ok(c) = ReservedChar::try_from(c) {
if c == ReservedChar::Slash && prev == ReservedChar::Star {
let ret = Some(builder(&source[*start_pos..pos - 1]));
None
}
-fn get_string<'a>(source: &'a str, iterator: &mut MyPeekable<'_>, start_pos: &mut usize,
- start: ReservedChar) -> Option<Token<'a>> {
+fn get_string<'a>(
+ source: &'a str,
+ iterator: &mut MyPeekable<'_>,
+ start_pos: &mut usize,
+ start: ReservedChar,
+) -> Option<Token<'a>> {
while let Some((pos, c)) = iterator.next() {
if c == '\\' {
// we skip next character
iterator.next();
- continue
+ continue;
}
if let Ok(c) = ReservedChar::try_from(c) {
if c == start {
None
}
+fn get_backtick_string<'a>(
+ source: &'a str,
+ iterator: &mut MyPeekable<'_>,
+ start_pos: &mut usize,
+) -> Option<Token<'a>> {
+ while let Some((pos, c)) = iterator.next() {
+ if c == '\\' {
+ // we skip next character
+ iterator.next();
+ continue;
+ }
+ if c == '$' && iterator.peek().map(|(_, c)| c == '{').unwrap_or(false) {
+ let mut count = 0;
+
+ loop {
+ if let Some((mut pos, c)) = iterator.next() {
+ if c == '\\' {
+ // we skip next character
+ iterator.next();
+ continue;
+ } else if c == '"' || c == '\'' {
+ // We don't care about the result
+ get_string(
+ source,
+ iterator,
+ &mut pos,
+ ReservedChar::try_from(c)
+ .expect("ReservedChar::try_from unexpectedly failed..."),
+ );
+ } else if c == '`' {
+ get_backtick_string(source, iterator, &mut pos);
+ } else if c == '{' {
+ count += 1;
+ } else if c == '}' {
+ count -= 1;
+ if count == 0 {
+ break;
+ }
+ }
+ } else {
+ return None;
+ }
+ }
+ } else if c == '`' {
+ let ret = Some(Token::String(&source[*start_pos..pos + 1]));
+ *start_pos = pos;
+ return ret;
+ }
+ }
+ None
+}
+
fn first_useful<'a>(v: &'a [Token<'a>]) -> Option<&'a Token<'a>> {
for x in v.iter().rev() {
if x.is_white_character() {
- continue
+ continue;
}
return Some(x);
}
}
}
-pub fn tokenize<'a>(source: &'a str) -> Tokens<'a> {
+pub fn tokenize(source: &str) -> Tokens<'_> {
let mut v = Vec::with_capacity(1000);
let mut start = 0;
let mut iterator = MyPeekable::new(source.char_indices());
Some(x) => x,
None => {
fill_other(source, &mut v, start, source.len());
- break
+ break;
}
};
if let Ok(c) = ReservedChar::try_from(c) {
}
}
if cont {
- continue
+ continue;
}
}
fill_other(source, &mut v, start, pos);
if let Some(s) = get_string(source, &mut iterator, &mut pos, c) {
v.push(s);
},
+ c == ReservedChar::BackTick =>
+ if let Some(s) = get_backtick_string(source, &mut iterator, &mut pos) {
+ v.push(s);
+ },
c == ReservedChar::Slash &&
v.last().unwrap_or(&Token::Other("")).eq_operation(Operation::Divide) => {
v.pop();
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let tokens = &self.0;
for i in 0..tokens.len() {
- if i > 0 &&
- tokens[i].requires_before() &&
- !tokens[i - 1].is_keyword() &&
- !tokens[i - 1].is_other() &&
- !tokens[i - 1].is_reserved_char() &&
- !tokens[i - 1].is_string() {
+ if i > 0
+ && tokens[i].requires_before()
+ && !tokens[i - 1].is_keyword()
+ && !tokens[i - 1].is_other()
+ && !tokens[i - 1].is_reserved_char()
+ && !tokens[i - 1].is_string()
+ {
write!(f, " ")?;
}
write!(f, "{}", tokens[i])?;
if let Some(c) = match tokens[i] {
- Token::Keyword(_) |
- Token::Other(_) if i + 1 < tokens.len() => tokens[i + 1].get_required(),
+ Token::Keyword(_) | Token::Other(_) if i + 1 < tokens.len() => {
+ tokens[i + 1].get_required()
+ }
_ => None,
} {
write!(f, "{}", c)?;
impl<'a> Tokens<'a> {
pub fn apply<F>(self, func: F) -> Tokens<'a>
- where F: Fn(Tokens<'a>) -> Tokens<'a> {
+ where
+ F: Fn(Tokens<'a>) -> Tokens<'a>,
+ {
func(self)
}
}
fn into_iter(mut self) -> Self::IntoIter {
self.0.reverse();
- IntoIterTokens {
- inner: self,
- }
+ IntoIterTokens { inner: self }
}
}
assert_eq!(::js::minify(source), expected_result);
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(v.0[3],
- Token::Regex {
- regex: "\"\\.x",
- is_global: true,
- is_interactive: false,
- });
+ assert_eq!(
+ v.0[3],
+ Token::Regex {
+ regex: "\"\\.x",
+ is_global: true,
+ is_interactive: false,
+ }
+ );
let source = r#"var x = /"\.x/gigigigig;var x = "hello";"#;
let expected_result = r#"var x=/"\.x/gi;var x="hello""#;
assert_eq!(::js::minify(source), expected_result);
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(v.0[3],
- Token::Regex {
- regex: "\"\\.x",
- is_global: true,
- is_interactive: true,
- });
+ assert_eq!(
+ v.0[3],
+ Token::Regex {
+ regex: "\"\\.x",
+ is_global: true,
+ is_interactive: true,
+ }
+ );
}
#[test]
assert_eq!(::js::minify(source), expected_result);
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(v.0[3],
- Token::Regex {
- regex: "\"\\.x\\/a",
- is_global: false,
- is_interactive: true,
- });
+ assert_eq!(
+ v.0[3],
+ Token::Regex {
+ regex: "\"\\.x\\/a",
+ is_global: false,
+ is_interactive: true,
+ }
+ );
let source = r#"var x = /\\/i;"#;
let expected_result = r#"var x=/\\/i"#;
assert_eq!(::js::minify(source), expected_result);
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(v.0[3],
- Token::Regex {
- regex: "\\\\",
- is_global: false,
- is_interactive: true,
- });
+ assert_eq!(
+ v.0[3],
+ Token::Regex {
+ regex: "\\\\",
+ is_global: false,
+ is_interactive: true,
+ }
+ );
+}
+
+#[test]
+fn even_more_regex() {
+ let source = r#"var x = /a-z /;"#;
+
+ let v = tokenize(source).apply(::js::clean_tokens);
+ assert_eq!(
+ v.0[3],
+ Token::Regex {
+ regex: "a-z ",
+ is_global: false,
+ is_interactive: false,
+ }
+ );
}
#[test]
let source = "( x ) / 2; x / y;x /= y";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Char(ReservedChar::OpenParenthese),
- Token::Other("x"),
- Token::Char(ReservedChar::CloseParenthese),
- Token::Operation(Operation::Divide),
- Token::Number(2),
- Token::Char(ReservedChar::SemiColon),
- Token::Other("x"),
- Token::Operation(Operation::Divide),
- Token::Other("y"),
- Token::Char(ReservedChar::SemiColon),
- Token::Other("x"),
- Token::Operation(Operation::DivideEqual),
- Token::Other("y")]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Char(ReservedChar::OpenParenthese),
+ Token::Other("x"),
+ Token::Char(ReservedChar::CloseParenthese),
+ Token::Operation(Operation::Divide),
+ Token::Number(2),
+ Token::Char(ReservedChar::SemiColon),
+ Token::Other("x"),
+ Token::Operation(Operation::Divide),
+ Token::Other("y"),
+ Token::Char(ReservedChar::SemiColon),
+ Token::Other("x"),
+ Token::Operation(Operation::DivideEqual),
+ Token::Other("y")
+ ]
+ );
+
+ let source = "let x = /x\ny/;";
+
+ let v = tokenize(source).apply(::js::clean_tokens);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Keyword(Keyword::Let),
+ Token::Other("x"),
+ Token::Operation(Operation::Equal),
+ Token::Operation(Operation::Divide),
+ Token::Other("x"),
+ Token::Other("y"),
+ Token::Operation(Operation::Divide)
+ ]
+ );
}
#[test]
let source = "true = == 2.3 === 32";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Keyword(Keyword::True),
- Token::Operation(Operation::Equal),
- Token::Condition(Condition::EqualTo),
- Token::FloatingNumber("2.3"),
- Token::Condition(Condition::SuperEqualTo),
- Token::Number(32)]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Keyword(Keyword::True),
+ Token::Operation(Operation::Equal),
+ Token::Condition(Condition::EqualTo),
+ Token::FloatingNumber("2.3"),
+ Token::Condition(Condition::SuperEqualTo),
+ Token::Number(32)
+ ]
+ );
}
#[test]
let source = "var x = 'hello people!'";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Keyword(Keyword::Var),
- Token::Other("x"),
- Token::Operation(Operation::Equal),
- Token::String("\'hello people!\'")]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Keyword(Keyword::Var),
+ Token::Other("x"),
+ Token::Operation(Operation::Equal),
+ Token::String("\'hello people!\'")
+ ]
+ );
}
#[test]
let source = "var x = .12; let y = 4.; var z = 12; .3 4. 'a' let u = 12.2";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Keyword(Keyword::Var),
- Token::Other("x"),
- Token::Operation(Operation::Equal),
- Token::FloatingNumber(".12"),
- Token::Char(ReservedChar::SemiColon),
- Token::Keyword(Keyword::Let),
- Token::Other("y"),
- Token::Operation(Operation::Equal),
- Token::FloatingNumber("4."),
- Token::Char(ReservedChar::SemiColon),
- Token::Keyword(Keyword::Var),
- Token::Other("z"),
- Token::Operation(Operation::Equal),
- Token::Number(12),
- Token::Char(ReservedChar::SemiColon),
- Token::FloatingNumber(".3"),
- Token::FloatingNumber("4."),
- Token::String("'a'"),
- Token::Keyword(Keyword::Let),
- Token::Other("u"),
- Token::Operation(Operation::Equal),
- Token::FloatingNumber("12.2")]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Keyword(Keyword::Var),
+ Token::Other("x"),
+ Token::Operation(Operation::Equal),
+ Token::FloatingNumber(".12"),
+ Token::Char(ReservedChar::SemiColon),
+ Token::Keyword(Keyword::Let),
+ Token::Other("y"),
+ Token::Operation(Operation::Equal),
+ Token::FloatingNumber("4."),
+ Token::Char(ReservedChar::SemiColon),
+ Token::Keyword(Keyword::Var),
+ Token::Other("z"),
+ Token::Operation(Operation::Equal),
+ Token::Number(12),
+ Token::Char(ReservedChar::SemiColon),
+ Token::FloatingNumber(".3"),
+ Token::FloatingNumber("4."),
+ Token::String("'a'"),
+ Token::Keyword(Keyword::Let),
+ Token::Other("u"),
+ Token::Operation(Operation::Equal),
+ Token::FloatingNumber("12.2")
+ ]
+ );
}
#[test]
let source = "var x = 12.a;";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Keyword(Keyword::Var),
- Token::Other("x"),
- Token::Operation(Operation::Equal),
- Token::Number(12),
- Token::Char(ReservedChar::Dot),
- Token::Other("a")]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Keyword(Keyword::Var),
+ Token::Other("x"),
+ Token::Operation(Operation::Equal),
+ Token::Number(12),
+ Token::Char(ReservedChar::Dot),
+ Token::Other("a")
+ ]
+ );
}
#[test]
let source = "t in e";
let v = tokenize(source).apply(::js::clean_tokens);
- assert_eq!(&v.0,
- &[Token::Other("t"),
- Token::Keyword(Keyword::In),
- Token::Other("e")]);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Other("t"),
+ Token::Keyword(Keyword::In),
+ Token::Other("e")
+ ]
+ );
+}
+
+#[test]
+fn division_by_id() {
+ let source = "100/abc";
+
+ let v = tokenize(source).apply(::js::clean_tokens);
+ assert_eq!(
+ &v.0,
+ &[
+ Token::Number(100),
+ Token::Operation(Operation::Divide),
+ Token::Other("abc")
+ ]
+ );
}