use std::fmt;
use super::{charstream::CharStream, Parse, ParseError};
pub trait Token: Parse + fmt::Display {}
pub trait Delimiter: Clone {
type Start: Token;
type End: Token;
fn new(start: Self::Start, end: Self::End) -> Self
where
Self: Sized;
fn span(&self) -> super::Span;
fn name() -> String;
}
#[derive(Clone)]
pub struct Chevron {
start: Less,
end: Greater,
}
impl Delimiter for Chevron {
type Start = Less;
type End = Greater;
fn new(start: Less, end: Greater) -> Self {
Self { start, end }
}
fn span(&self) -> super::Span {
super::Span::new(self.start.span().start, self.end.span().end)
}
fn name() -> String {
"<>".to_string()
}
}
macro_rules! create_tokens {
($($token:tt $id:ident),+) => {
$(
#[derive(Clone)]
pub struct $id {
span: super::Span
}
impl Token for $id {}
impl Parse for $id {
fn parse(value: &mut CharStream) -> Result<Self, ParseError> where Self: Sized {
let token = stringify!($token);
let len = token.len();
let start = value.pos();
let mut token_value = value.clone();
let mut mtch = String::new();
while mtch.len() < len {
mtch.push(match token_value.next() {
Some(value) => value,
None => break
});
}
if (token == mtch) {
value.goto(token_value.pos())?;
let end = value.pos();
return Ok(Self { span: super::Span::new(start, end)});
}
Err(ParseError(format!("Could not find token '{}'.", stringify!($token)), token_value.pos()))
}
fn span(&self) -> super::Span {
self.span.clone()
}
}
impl fmt::Debug for $id {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
write!(f, "Token({}, at: {})", stringify!($token), self.span.end)
}
}
impl fmt::Display for $id {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Token({})", stringify!($token))
}
}
)+
};
}
macro_rules! create_delimiters {
($($token:tt $left: ident $right: ident $delim:ident),+) => {
$(
#[derive(Clone)]
pub struct $left {
span: super::Span
}
impl Token for $left {}
impl Parse for $left {
fn parse(value: &mut CharStream) -> Result<Self, ParseError> where Self: Sized {
let chr = stringify!($token).chars().nth(0).unwrap();
let mut token_value = value.clone();
let start = value.pos();
if let Some(token) = token_value.next() {
if token == chr {
value.goto(token_value.pos())?;
let end = value.pos();
return Ok(Self { span: super::Span::new(start, end)})
}
}
Err(ParseError(format!("could not find left side of: '{}'.", stringify!($token)), value.pos()))
}
fn span(&self) -> super::Span {
self.span.clone()
}
}
impl fmt::Debug for $left {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Token({})", stringify!($token).chars().nth(0).unwrap())
}
}
impl fmt::Display for $left {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Token({})", stringify!($token).chars().nth(0).unwrap())
}
}
#[derive(Clone)]
pub struct $right {
span: super::Span
}
impl Token for $right {}
impl Parse for $right {
fn parse(value: &mut CharStream) -> Result<Self, ParseError> where Self: Sized {
let chr = stringify!($token).chars().nth(1).unwrap();
let mut token_value = value.clone();
let start = value.pos();
if let Some(token) = token_value.next() {
if token == chr {
value.goto(token_value.pos())?;
let end = value.pos();
return Ok(Self { span: super::Span::new(start, end)})
}
}
Err(ParseError(format!("could not find right side of: '{}'.", stringify!($token)), value.pos()))
}
fn span(&self) -> super::Span {
self.span.clone()
}
}
impl fmt::Debug for $right {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Token({})", stringify!($token).chars().nth(1).unwrap())
}
}
impl fmt::Display for $right {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Token({})", stringify!($token).chars().nth(1).unwrap())
}
}
#[derive(Debug, Clone)]
pub struct $delim {
start: $left,
end: $right
}
impl Delimiter for $delim {
type Start = $left;
type End = $right;
fn new(start: Self::Start, end: Self::End) -> Self {
Self { start, end }
}
fn span(&self) -> super::Span {
super::Span::new(self.start.span().start, self.end.span().end)
}
fn name() -> String {
String::from(stringify!($delim))
}
}
)+
};
}
create_tokens! {
, Comma,
. Period,
! Bang,
# Hash,
$ Dollar,
% Percentage,
^ UpArrow,
& Ampersand,
* Asterisk,
_ UnderScore,
- Hyphen,
+ Plus,
= Equal,
== EqualEqual,
: Colon,
:: DoubleColon,
; Semicolon,
| Pipe,
< Less,
> Greater,
/ ForwardSlash,
-> RightArrow,
=> FatArrow
}
create_delimiters! {
() LeftParen RightParen Paren,
{} LeftBrace RightBrace Brace,
[] LeftBracket RightBracket Bracket,
"" LeftQuote RightQuote Quote
}