use std::fmt;
impl Token {
pub fn literal_value(&self) -> String {
match &self.val {
TokenVal::Var(word) | TokenVal::Const(word) => word.to_owned(),
_ => unreachable!(
"{}:{} should not be called in this kind of token",
self.row, self.col
),
}
}
}
#[derive(Clone)]
pub struct Token {
pub row: usize, pub col: usize, pub val: TokenVal,
}
#[derive(Clone)]
pub enum TokenVal {
Var(String), Const(String),
SubCmd(Vec<TokenVal>), Pipe, OpenPar, ClosePar, OpenBra, CloseBra, Less, Equal, More, And,
}
pub type Tokens = Vec<Token>;
pub fn print_tokens(tokens: &Tokens) {
print!("{}", tokens_to_string(tokens));
}
pub fn tokens_to_string(tokens: &Tokens) -> String {
let len = tokens.len();
if len == 0 {
return "(no tokens)".to_owned();
}
let mut row = 1;
let mut res = String::new();
for token in tokens {
if token.row > row {
row = token.row;
let s = format!(" \n{row}: ");
res.push_str(&s);
}
let s = format!("{} ", token.val);
res.push_str(&s);
}
let nbr = res.len();
res[1..nbr].to_string()
}
pub fn from_u8(char: u8) -> TokenVal {
match char as char {
'(' => TokenVal::OpenPar,
')' => TokenVal::ClosePar,
'{' => TokenVal::OpenBra,
'}' => TokenVal::CloseBra,
'|' => TokenVal::Pipe,
'&' => TokenVal::And,
'<' => TokenVal::Less,
'=' => TokenVal::Equal,
'>' => TokenVal::More,
_ => panic!("unreacheable should not be called on {}", char as char),
}
}
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.val {
TokenVal::Const(s) | TokenVal::Var(s) => {
write!(f, "'{}' at {}:{}", s, self.row, self.col)
}
_ => unreachable!("should only be called on consts or vars"),
}
}
}
impl TokenVal {
fn to_string(&self) -> String {
match self {
TokenVal::OpenPar => "(".to_string(),
TokenVal::ClosePar => ")".to_string(),
TokenVal::OpenBra => "{".to_string(),
TokenVal::CloseBra => "}".to_string(),
TokenVal::Pipe => "|".to_string(),
TokenVal::And => "&".to_string(),
TokenVal::Less => "<".to_string(),
TokenVal::Equal => "=".to_string(),
TokenVal::More => ">".to_string(),
_ => panic!("unreachable called on unexpexted token"),
}
}
pub fn var_or_const_from_u8(bytes: &[u8]) -> Self {
let val = std::str::from_utf8(bytes).unwrap().to_owned();
if val.contains("$") {
TokenVal::Var(val)
} else {
TokenVal::Const(val)
}
}
pub fn is_function(&self) -> bool {
if let TokenVal::Const(s) = self {
return s == "function";
}
return false;
}
pub fn get_word_content(&self) -> String {
match self {
TokenVal::Var(s) | TokenVal::Const(s) => s.to_owned(),
_ => panic!("get_word_content must only be used after validating the token is a word"),
}
}
}
impl fmt::Display for TokenVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TokenVal::Var(s) => write!(f, "Var({})", s),
TokenVal::Const(s) => write!(f, "Const({})", s),
TokenVal::OpenPar
| TokenVal::ClosePar
| TokenVal::OpenBra
| TokenVal::CloseBra
| TokenVal::Less
| TokenVal::Equal
| TokenVal::More
| TokenVal::And
| TokenVal::Pipe => write!(f, "{}", self.to_string()),
TokenVal::SubCmd(tokens) => {
let mut res = String::new();
for tok in tokens {
res = format!("{}{}, ", res, tok);
}
let n = res.len();
write!(f, "SubCmd([{}])", &res[..n - 2])
}
}
}
}