use std::fmt;
use std::fmt::{Display, Debug, Formatter};
use std::str::FromStr;
use joker::track::*;
use joker::token::{TokenData, Token};
use joker::word::Reserved;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Semi {
Inserted,
Explicit(Option<Posn>)
}
impl Untrack for Semi {
fn untrack(&mut self) {
*self = Semi::Explicit(None);
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum UnopTag {
Minus,
Plus,
Not,
BitNot,
Typeof,
Void,
Delete
}
impl FromStr for UnopTag {
type Err = ();
fn from_str(s: &str) -> Result<UnopTag, ()> {
Ok(match s {
"-" => UnopTag::Minus,
"+" => UnopTag::Plus,
"!" => UnopTag::Not,
"~" => UnopTag::BitNot,
"typeof" => UnopTag::Typeof,
"void" => UnopTag::Void,
"delete" => UnopTag::Delete,
_ => { return Err(()); }
})
}
}
#[derive(PartialEq, Eq)]
pub struct Op<T> {
pub location: Option<Span>,
pub tag: T
}
impl<T: FromStr> FromStr for Op<T> {
type Err = ();
fn from_str(s: &str) -> Result<Op<T>, ()> {
match T::from_str(s) {
Ok(tag) => Ok(Op { location: None, tag: tag }),
Err(_) => Err(())
}
}
}
impl<T> TrackingRef for Op<T> {
fn tracking_ref(&self) -> &Option<Span> { &self.location }
}
impl<T> TrackingMut for Op<T> {
fn tracking_mut(&mut self) -> &mut Option<Span> { &mut self.location }
}
impl<T: Debug> Debug for Op<T> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.debug_struct("Op")
.field("tag", &self.tag)
.finish()
}
}
impl<T: Display> Display for Op<T> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
self.tag.fmt(fmt)
}
}
pub type Unop = Op<UnopTag>;
impl<T> Untrack for Op<T> {
fn untrack(&mut self) {
self.location = None;
}
}
pub trait Precedence {
fn precedence(&self) -> u32;
}
impl<T: Precedence> Precedence for Op<T> {
fn precedence(&self) -> u32 {
self.tag.precedence()
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum BinopTag {
Eq,
NEq,
StrictEq,
StrictNEq,
Lt,
LEq,
Gt,
GEq,
LShift,
RShift,
URShift,
Plus,
Minus,
Times,
Div,
Mod,
BitOr,
BitXor,
BitAnd,
In,
Instanceof,
}
impl FromStr for BinopTag {
type Err = ();
fn from_str(s: &str) -> Result<BinopTag, ()> {
Ok(match s {
"==" => BinopTag::Eq,
"!=" => BinopTag::NEq,
"===" => BinopTag::StrictEq,
"!==" => BinopTag::StrictNEq,
"<" => BinopTag::Lt,
"<=" => BinopTag::LEq,
">" => BinopTag::Gt,
">=" => BinopTag::GEq,
"<<" => BinopTag::LShift,
">>" => BinopTag::RShift,
">>>" => BinopTag::URShift,
"+" => BinopTag::Plus,
"-" => BinopTag::Minus,
"*" => BinopTag::Times,
"/" => BinopTag::Div,
"%" => BinopTag::Mod,
"|" => BinopTag::BitOr,
"^" => BinopTag::BitXor,
"&" => BinopTag::BitAnd,
"in" => BinopTag::In,
"instanceof" => BinopTag::Instanceof,
_ => { return Err(()); }
})
}
}
impl Precedence for BinopTag {
fn precedence(&self) -> u32 {
match *self {
BinopTag::Eq => 7,
BinopTag::NEq => 7,
BinopTag::StrictEq => 7,
BinopTag::StrictNEq => 7,
BinopTag::Lt => 8,
BinopTag::LEq => 8,
BinopTag::Gt => 8,
BinopTag::GEq => 8,
BinopTag::LShift => 9,
BinopTag::RShift => 9,
BinopTag::URShift => 9,
BinopTag::Plus => 10,
BinopTag::Minus => 10,
BinopTag::Times => 11,
BinopTag::Div => 11,
BinopTag::Mod => 11,
BinopTag::BitOr => 4,
BinopTag::BitXor => 5,
BinopTag::BitAnd => 6,
BinopTag::In => 8,
BinopTag::Instanceof => 8,
}
}
}
pub type Binop = Op<BinopTag>;
impl Display for BinopTag {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str(match *self {
BinopTag::Eq => "==",
BinopTag::NEq => "!=",
BinopTag::StrictEq => "===",
BinopTag::StrictNEq => "!==",
BinopTag::Lt => "<",
BinopTag::LEq => "<=",
BinopTag::Gt => ">",
BinopTag::GEq => ">=",
BinopTag::LShift => "<<",
BinopTag::RShift => ">>",
BinopTag::URShift => ">>>",
BinopTag::Plus => "+",
BinopTag::Minus => "-",
BinopTag::Times => "*",
BinopTag::Div => "/",
BinopTag::Mod => "%",
BinopTag::BitOr => "|",
BinopTag::BitXor => "^",
BinopTag::BitAnd => "&",
BinopTag::In => "in",
BinopTag::Instanceof => "instanceof"
})
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum LogopTag {
Or,
And
}
impl FromStr for LogopTag {
type Err = ();
fn from_str(s: &str) -> Result<LogopTag, ()> {
Ok(match s {
"||" => LogopTag::Or,
"&&" => LogopTag::And,
_ => { return Err(()); }
})
}
}
impl Precedence for LogopTag {
fn precedence(&self) -> u32 {
match *self {
LogopTag::Or => 2,
LogopTag::And => 3
}
}
}
pub type Logop = Op<LogopTag>;
impl Display for LogopTag {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str(match *self {
LogopTag::Or => "||",
LogopTag::And => "&&"
})
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum AssopTag {
Eq,
PlusEq,
MinusEq,
TimesEq,
DivEq,
ModEq,
LShiftEq,
RShiftEq,
URShiftEq,
BitOrEq,
BitXorEq,
BitAndEq
}
impl FromStr for AssopTag {
type Err = ();
fn from_str(s: &str) -> Result<AssopTag, ()> {
Ok(match s {
"=" => AssopTag::Eq,
"+=" => AssopTag::PlusEq,
"-=" => AssopTag::MinusEq,
"*=" => AssopTag::TimesEq,
"/=" => AssopTag::DivEq,
"%=" => AssopTag::ModEq,
"<<=" => AssopTag::LShiftEq,
">>=" => AssopTag::RShiftEq,
">>>=" => AssopTag::URShiftEq,
"|=" => AssopTag::BitOrEq,
"^=" => AssopTag::BitXorEq,
"&=" => AssopTag::BitAndEq,
_ => { return Err(()); }
})
}
}
impl Precedence for AssopTag {
fn precedence(&self) -> u32 { 0 }
}
pub type Assop = Op<AssopTag>;
impl Display for AssopTag {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str(match *self {
AssopTag::Eq => "=",
AssopTag::PlusEq => "+=",
AssopTag::MinusEq => "-=",
AssopTag::TimesEq => "*=",
AssopTag::DivEq => "/=",
AssopTag::ModEq => "%=",
AssopTag::LShiftEq => "<<=",
AssopTag::RShiftEq => ">>=",
AssopTag::URShiftEq => ">>>=",
AssopTag::BitOrEq => "|=",
AssopTag::BitXorEq => "^=",
AssopTag::BitAndEq => "&="
})
}
}
pub trait ToOp {
fn to_binop(&self, bool) -> Option<Binop>;
fn to_logop(&self) -> Option<Logop>;
fn to_assop(&self) -> Option<Assop>;
}
impl ToOp for Token {
fn to_binop(&self, allow_in: bool) -> Option<Binop> {
Some(Op {
location: Some(self.location),
tag: match self.value {
TokenData::Star => BinopTag::Times,
TokenData::Slash => BinopTag::Div,
TokenData::Mod => BinopTag::Mod,
TokenData::Plus => BinopTag::Plus,
TokenData::Minus => BinopTag::Minus,
TokenData::LShift => BinopTag::LShift,
TokenData::RShift => BinopTag::RShift,
TokenData::URShift => BinopTag::URShift,
TokenData::LAngle => BinopTag::Lt,
TokenData::RAngle => BinopTag::Gt,
TokenData::LEq => BinopTag::LEq,
TokenData::GEq => BinopTag::GEq,
TokenData::Reserved(Reserved::Instanceof) => BinopTag::Instanceof,
TokenData::Reserved(Reserved::In) if allow_in => BinopTag::In,
TokenData::Eq => BinopTag::Eq,
TokenData::NEq => BinopTag::NEq,
TokenData::StrictEq => BinopTag::StrictEq,
TokenData::StrictNEq => BinopTag::StrictNEq,
TokenData::BitAnd => BinopTag::BitAnd,
TokenData::BitXor => BinopTag::BitXor,
TokenData::BitOr => BinopTag::BitOr,
_ => { return None; }
}
})
}
fn to_logop(&self) -> Option<Logop> {
Some(Op {
location: Some(self.location),
tag: match self.value {
TokenData::LogicalAnd => LogopTag::And,
TokenData::LogicalOr => LogopTag::Or,
_ => { return None; }
}
})
}
fn to_assop(&self) -> Option<Assop> {
Some(Op {
location: Some(self.location),
tag: match self.value {
TokenData::Assign => AssopTag::Eq,
TokenData::PlusAssign => AssopTag::PlusEq,
TokenData::MinusAssign => AssopTag::MinusEq,
TokenData::StarAssign => AssopTag::TimesEq,
TokenData::SlashAssign => AssopTag::DivEq,
TokenData::ModAssign => AssopTag::ModEq,
TokenData::LShiftAssign => AssopTag::LShiftEq,
TokenData::RShiftAssign => AssopTag::RShiftEq,
TokenData::URShiftAssign => AssopTag::URShiftEq,
TokenData::BitAndAssign => AssopTag::BitAndEq,
TokenData::BitOrAssign => AssopTag::BitOrEq,
TokenData::BitXorAssign => AssopTag::BitXorEq,
_ => { return None; }
}
})
}
}