use std::{
fmt::{ Display, Debug, Formatter, Result as FMTResult, },
str::from_utf8_unchecked as str_from_utf8_unchecked,
slice::Iter as SliceIter,
cmp::Ordering,
hash::{ Hash, Hasher, },
borrow::{ Borrow, },
};
use crate::{
util::Either,
};
#[derive(Clone)]
pub struct Identifier {
vec: Vec<u8>,
}
impl Display for Identifier {
fn fmt (&self, f: &mut Formatter) -> FMTResult {
write!(f, "{}", self.as_ref())
}
}
impl Debug for Identifier {
fn fmt (&self, f: &mut Formatter) -> FMTResult {
Display::fmt(self, f)
}
}
impl Default for Identifier {
#[inline] fn default () -> Self { Self::new() }
}
impl PartialEq for Identifier {
#[inline] fn eq (&self, other: &Self) -> bool { self.as_ref() == other.as_ref() }
}
impl Eq for Identifier { }
impl PartialOrd for Identifier {
#[inline] fn partial_cmp (&self, other: &Self) -> Option<Ordering> { self.as_ref().partial_cmp(other.as_ref()) }
}
impl Ord for Identifier {
#[inline] fn cmp (&self, other: &Self) -> Ordering { self.as_ref().cmp(other.as_ref()) }
}
impl Hash for Identifier {
#[inline] fn hash<H: Hasher> (&self, hasher: &mut H) { self.as_ref().hash(hasher) }
}
pub struct IdentifierChars<'a> {
identifier: &'a Identifier,
index: usize,
}
impl<'a> Iterator for IdentifierChars<'a> {
type Item = char;
fn next (&mut self) -> Option<Self::Item> {
let ch = self.identifier.get(self.index);
if ch.is_some() { self.index += 1 }
ch
}
}
impl Identifier {
pub const MAX_LENGTH: usize = 64;
pub fn new () -> Self {
Self { vec: Vec::new() }
}
#[inline]
pub fn len (&self) -> usize {
self.vec.len()
}
#[inline]
pub fn is_empty (&self) -> bool {
self.len() == 0
}
pub fn set<S: AsRef<str>> (&mut self, s: &S) -> bool {
let s = s.as_ref();
if s.len() > Self::MAX_LENGTH { return false }
for ch in s.chars() {
if !ch.is_ascii() { return false }
}
self.vec.clear();
for ch in s.chars() {
self.vec.push(ch as u8);
}
true
}
pub fn append (&mut self, c: char) -> bool {
if self.len() < Self::MAX_LENGTH && c.is_ascii() {
self.vec.push(c as u8);
true
} else {
false
}
}
pub fn get (&self, index: usize) -> Option<char> {
self.vec.get(index).map(|ch| *ch as _)
}
pub fn char_iter (&self) -> IdentifierChars<'_> {
IdentifierChars { identifier: self, index: 0 }
}
pub fn byte_iter (&self) -> SliceIter<u8> {
self.vec.iter()
}
pub fn as_str (&self) -> &str {
self.as_ref()
}
}
impl AsRef<str> for Identifier {
#[inline] fn as_ref (&self) -> &str { unsafe { str_from_utf8_unchecked(self.vec.as_slice()) } }
}
impl From<&str> for Identifier {
#[inline]
fn from (s: &str) -> Self {
let mut i = Self::new();
i.set(&s);
i
}
}
impl Into<String> for Identifier {
#[inline] fn into (self) -> String { self.as_ref().to_owned() }
}
impl Into<String> for &Identifier {
#[inline] fn into (self) -> String { self.as_ref().to_owned() }
}
impl Borrow<str> for Identifier {
#[inline] fn borrow (&self) -> &str { self.as_ref() }
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[allow(missing_docs)]
pub enum Number {
Integer(u64),
FloatingPoint(f64),
}
impl From<u64> for Number {
#[inline]
fn from (i: u64) -> Self {
Number::Integer(i)
}
}
impl From<f64> for Number {
#[inline]
fn from (f: f64) -> Self {
Number::FloatingPoint(f)
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[allow(missing_docs)]
pub enum Keyword {
Import,
Export,
Module,
Global,
Function,
From,
If,
Else,
Let,
}
impl Keyword {
pub fn value (self) -> &'static str {
use Keyword::*;
match self {
Import => "import",
Export => "export",
Module => "mod",
Global => "global",
Function => "fn",
From => "from",
If => "if",
Else => "else",
Let => "let",
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[allow(missing_docs)]
pub enum Operator {
Not,
And,
Xor,
Or,
As,
DoubleColon,
RightArrow,
AssignAdd,
AssignSub,
AssignMul,
AssignDiv,
AssignRem,
Equal,
NotEqual,
GreaterOrEqual,
LesserOrEqual,
Greater,
Lesser,
Assign,
Add,
Sub,
Mul,
Div,
Rem,
AddressOf,
Dereference,
Comma,
Colon,
Semi,
LeftParen,
RightParen,
LeftBracket,
RightBracket,
}
impl Operator {
pub fn value (self) -> &'static str {
use Operator::*;
match self {
Not => "not",
And => "and",
Xor => "xor",
Or => "or",
As => "as",
DoubleColon => "::",
RightArrow => "->",
AssignAdd => "+=",
AssignSub => "-=",
AssignMul => "*=",
AssignDiv => "/=",
AssignRem => "%=",
Equal => "==",
NotEqual => "!=",
GreaterOrEqual => ">=",
LesserOrEqual => "<=",
Greater => ">",
Lesser => "<",
Assign => "=",
Add => "+",
Sub => "-",
Mul => "*",
Div => "/",
Rem => "%",
AddressOf => "^",
Dereference => "@",
Comma => ",",
Colon => ":",
Semi => ";",
LeftParen => "(",
RightParen => ")",
LeftBracket => "{",
RightBracket => "}",
}
}
}
pub const IDENTIFIER_VALUES: &[(&str, Either<Keyword, Operator>)] = {
&[
("import", Either::A(Keyword::Import)),
("export", Either::A(Keyword::Export)),
("global", Either::A(Keyword::Global)),
("from", Either::A(Keyword::From)),
("else", Either::A(Keyword::Else)),
("let", Either::A(Keyword::Let)),
("not", Either::B(Operator::Not)),
("and", Either::B(Operator::And)),
("xor", Either::B(Operator::Xor)),
("mod", Either::A(Keyword::Module)),
("fn", Either::A(Keyword::Function)),
("if", Either::A(Keyword::If)),
("or", Either::B(Operator::Or)),
("as", Either::B(Operator::As)),
]
};
pub const SYM_OPERATOR_VALUES: &[(&str, Operator)] = {
use Operator::*;
&[
("::", DoubleColon),
("->", RightArrow),
("+=", AssignAdd),
("-=", AssignSub),
("*=", AssignMul),
("/=", AssignDiv),
("%=", AssignRem),
("==", Equal),
("!=", NotEqual),
(">=", GreaterOrEqual),
("<=", LesserOrEqual),
(">", Greater),
("<", Lesser),
("=", Assign),
("+", Add),
("-", Sub),
("*", Mul),
("/", Div),
("%", Rem),
("^", AddressOf),
("@", Dereference),
(",", Comma),
(":", Colon),
(";", Semi),
("(", LeftParen),
(")", RightParen),
("{", LeftBracket),
("}", RightBracket),
]
};
pub const STATEMENT_KEYWORDS: &[Keyword] = {
use Keyword::*;
&[
Let,
If,
]
};
pub const ITEM_KEYWORDS: &[Keyword] = {
use Keyword::*;
&[
Module,
Global,
Function,
]
};
pub const BINARY_PRECEDENCES: &[(Operator, usize)] = {
use Operator::*;
&[
(And, 20),
(Or, 20),
(Xor, 20),
(Equal, 30),
(NotEqual, 30),
(Lesser, 30),
(Greater, 30),
(LesserOrEqual, 30),
(GreaterOrEqual, 30),
(Add, 50),
(Sub, 50),
(Mul, 60),
(Div, 60),
(Rem, 60),
(LeftParen, 70),
]
};
pub const fn get_binary_precedence (operator: Operator) -> usize {
let mut i = 0;
loop {
let (op, prec) = BINARY_PRECEDENCES[i];
if op as u8 == operator as u8 { return prec }
i += 1;
}
}