use enum_map::Enum;
use strum::IntoStaticStr;
use crate::AssignTarget;
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Enum, IntoStaticStr)]
#[strum(serialize_all = "snake_case")] pub enum Code {
UnPos, UnNeg, UnCpl, UnNot, UnVoid,
UnTypeof,
UnDelete,
UnPreDec,
UnPreInc,
UnPostDec,
UnPostInc,
BinAdd,
BinSub,
BinMul,
BinDiv,
BinRem,
BinPow,
BinLt,
BinLe,
BinGt,
BinGe,
BinIn,
BinInstanceof,
BinShl,
BinShr,
BinUShr,
BinLooseEq,
BinLooseNe,
BinStrictEq,
BinStrictNe,
BinNullishCoalescing,
BinLogicalOr,
BinLogicalAnd,
BinBitwiseOr,
BinBitwiseAnd,
BinBitwiseXor,
BinComma,
BinAssign,
BinAddAssign,
BinSubAssign,
BinMulAssign,
BinDivAssign,
BinRemAssign,
BinPowAssign,
BinShlAssign,
BinShrAssign,
BinUShrAssign,
BinBitwiseOrAssign,
BinBitwiseAndAssign,
BinBitwiseXorAssign,
BinNullishCoalescingAssign,
BinLogicalOrAssign,
BinLogicalAndAssign,
}
impl Code {
pub fn unary_assign_target(code: Code) -> AssignTarget {
if (code as u8) >= (Code::UnPreDec as u8) && (code as u8) <= (Code::UnPostInc as u8) {
return AssignTarget::Update;
}
AssignTarget::None
}
pub fn is_left_associative(code: Code) -> bool {
(code as u8) >= (Code::BinAdd as u8)
&& (code as u8) < (Code::BinComma as u8)
&& code != Code::BinPow
}
pub fn is_right_associative(code: Code) -> bool {
(code as u8) >= (Code::BinAssign as u8) || code == Code::BinPow
}
pub fn binary_assign_target(self) -> AssignTarget {
let code = self;
if code == Code::BinAssign {
return AssignTarget::Replace;
}
if (code as u8) > (Code::BinAssign as u8) {
return AssignTarget::Update;
}
AssignTarget::None
}
pub fn is_prefix(code: Code) -> bool {
(code as u8) < (Code::UnPostDec as u8)
}
}
#[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Level {
Lowest,
Comma,
Spread,
Yield,
Assign,
Conditional,
NullishCoalescing,
LogicalOr,
LogicalAnd,
BitwiseOr,
BitwiseXor,
BitwiseAnd,
Equals,
Compare,
Shift,
Add,
Multiply,
Exponentiation,
Prefix,
Postfix,
New,
Call,
Member,
}
impl Level {
#[inline]
pub fn lt(self, b: Level) -> bool {
(self as u8) < (b as u8)
}
#[inline]
pub fn gt(self, b: Level) -> bool {
(self as u8) > (b as u8)
}
#[inline]
pub fn gte(self, b: Level) -> bool {
(self as u8) >= (b as u8)
}
#[inline]
pub fn lte(self, b: Level) -> bool {
(self as u8) <= (b as u8)
}
#[inline]
pub fn eql(self, b: Level) -> bool {
(self as u8) == (b as u8)
}
#[inline]
pub fn sub(self, i: u8) -> Level {
Level::from_raw((self as u8) - i)
}
#[inline]
pub fn add_f(self, i: u8) -> Level {
Level::from_raw((self as u8) + i)
}
#[inline]
const fn from_raw(n: u8) -> Level {
match n {
0 => Level::Lowest,
1 => Level::Comma,
2 => Level::Spread,
3 => Level::Yield,
4 => Level::Assign,
5 => Level::Conditional,
6 => Level::NullishCoalescing,
7 => Level::LogicalOr,
8 => Level::LogicalAnd,
9 => Level::BitwiseOr,
10 => Level::BitwiseXor,
11 => Level::BitwiseAnd,
12 => Level::Equals,
13 => Level::Compare,
14 => Level::Shift,
15 => Level::Add,
16 => Level::Multiply,
17 => Level::Exponentiation,
18 => Level::Prefix,
19 => Level::Postfix,
20 => Level::New,
21 => Level::Call,
22 => Level::Member,
_ => panic!("invalid Op.Level"),
}
}
}
#[derive(Copy, Clone)]
pub struct Op {
pub text: &'static [u8],
pub level: Level,
pub is_keyword: bool,
}
impl Default for Op {
fn default() -> Self {
Op {
text: b"",
level: Level::Lowest,
is_keyword: false,
}
}
}
impl Op {
pub const fn init(text: &'static [u8], level: Level, is_keyword: bool) -> Op {
Op {
text,
level,
is_keyword,
}
}
}
pub type TableType = Table;
#[repr(transparent)]
pub struct Table(pub [Op; <Code as Enum>::LENGTH]);
impl Table {
#[inline]
pub fn get_ptr_const(&'static self, code: Code) -> &'static Op {
&self.0[code as usize]
}
#[inline]
pub fn get(&self, code: Code) -> Op {
self.0[code as usize]
}
}
impl core::ops::Index<Code> for Table {
type Output = Op;
#[inline]
fn index(&self, code: Code) -> &Op {
&self.0[code as usize]
}
}
pub static TABLE: Table = Table({
const NIL: Op = Op::init(b"", Level::Lowest, false);
let mut t = [NIL; <Code as Enum>::LENGTH];
t[Code::UnPos as usize] = Op::init(b"+", Level::Prefix, false);
t[Code::UnNeg as usize] = Op::init(b"-", Level::Prefix, false);
t[Code::UnCpl as usize] = Op::init(b"~", Level::Prefix, false);
t[Code::UnNot as usize] = Op::init(b"!", Level::Prefix, false);
t[Code::UnVoid as usize] = Op::init(b"void", Level::Prefix, true);
t[Code::UnTypeof as usize] = Op::init(b"typeof", Level::Prefix, true);
t[Code::UnDelete as usize] = Op::init(b"delete", Level::Prefix, true);
t[Code::UnPreDec as usize] = Op::init(b"--", Level::Prefix, false);
t[Code::UnPreInc as usize] = Op::init(b"++", Level::Prefix, false);
t[Code::UnPostDec as usize] = Op::init(b"--", Level::Postfix, false);
t[Code::UnPostInc as usize] = Op::init(b"++", Level::Postfix, false);
t[Code::BinAdd as usize] = Op::init(b"+", Level::Add, false);
t[Code::BinSub as usize] = Op::init(b"-", Level::Add, false);
t[Code::BinMul as usize] = Op::init(b"*", Level::Multiply, false);
t[Code::BinDiv as usize] = Op::init(b"/", Level::Multiply, false);
t[Code::BinRem as usize] = Op::init(b"%", Level::Multiply, false);
t[Code::BinPow as usize] = Op::init(b"**", Level::Exponentiation, false);
t[Code::BinLt as usize] = Op::init(b"<", Level::Compare, false);
t[Code::BinLe as usize] = Op::init(b"<=", Level::Compare, false);
t[Code::BinGt as usize] = Op::init(b">", Level::Compare, false);
t[Code::BinGe as usize] = Op::init(b">=", Level::Compare, false);
t[Code::BinIn as usize] = Op::init(b"in", Level::Compare, true);
t[Code::BinInstanceof as usize] = Op::init(b"instanceof", Level::Compare, true);
t[Code::BinShl as usize] = Op::init(b"<<", Level::Shift, false);
t[Code::BinShr as usize] = Op::init(b">>", Level::Shift, false);
t[Code::BinUShr as usize] = Op::init(b">>>", Level::Shift, false);
t[Code::BinLooseEq as usize] = Op::init(b"==", Level::Equals, false);
t[Code::BinLooseNe as usize] = Op::init(b"!=", Level::Equals, false);
t[Code::BinStrictEq as usize] = Op::init(b"===", Level::Equals, false);
t[Code::BinStrictNe as usize] = Op::init(b"!==", Level::Equals, false);
t[Code::BinNullishCoalescing as usize] = Op::init(b"??", Level::NullishCoalescing, false);
t[Code::BinLogicalOr as usize] = Op::init(b"||", Level::LogicalOr, false);
t[Code::BinLogicalAnd as usize] = Op::init(b"&&", Level::LogicalAnd, false);
t[Code::BinBitwiseOr as usize] = Op::init(b"|", Level::BitwiseOr, false);
t[Code::BinBitwiseAnd as usize] = Op::init(b"&", Level::BitwiseAnd, false);
t[Code::BinBitwiseXor as usize] = Op::init(b"^", Level::BitwiseXor, false);
t[Code::BinComma as usize] = Op::init(b",", Level::Comma, false);
t[Code::BinAssign as usize] = Op::init(b"=", Level::Assign, false);
t[Code::BinAddAssign as usize] = Op::init(b"+=", Level::Assign, false);
t[Code::BinSubAssign as usize] = Op::init(b"-=", Level::Assign, false);
t[Code::BinMulAssign as usize] = Op::init(b"*=", Level::Assign, false);
t[Code::BinDivAssign as usize] = Op::init(b"/=", Level::Assign, false);
t[Code::BinRemAssign as usize] = Op::init(b"%=", Level::Assign, false);
t[Code::BinPowAssign as usize] = Op::init(b"**=", Level::Assign, false);
t[Code::BinShlAssign as usize] = Op::init(b"<<=", Level::Assign, false);
t[Code::BinShrAssign as usize] = Op::init(b">>=", Level::Assign, false);
t[Code::BinUShrAssign as usize] = Op::init(b">>>=", Level::Assign, false);
t[Code::BinBitwiseOrAssign as usize] = Op::init(b"|=", Level::Assign, false);
t[Code::BinBitwiseAndAssign as usize] = Op::init(b"&=", Level::Assign, false);
t[Code::BinBitwiseXorAssign as usize] = Op::init(b"^=", Level::Assign, false);
t[Code::BinNullishCoalescingAssign as usize] = Op::init(b"??=", Level::Assign, false);
t[Code::BinLogicalOrAssign as usize] = Op::init(b"||=", Level::Assign, false);
t[Code::BinLogicalAndAssign as usize] = Op::init(b"&&=", Level::Assign, false);
t
});