use std::fmt::{Display, Formatter, Result};
use std::sync::Arc;
use std::vec::IntoIter;
use crate::{Span, Spanned, lexer::punctuation_would_merge};
#[path = "token_stream/delim.rs"]
pub mod delim;
use delim::{Delimiter, DelimiterKind};
#[path = "token_stream/punct.rs"]
mod punct;
pub use punct::Punct;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LiteralKind {
String,
RawString,
Integer,
Float,
}
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub struct LiteralToken {
pub kind: LiteralKind,
span: Span,
}
impl Display for LiteralToken {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
formatter.write_str(self.text())
}
}
impl LiteralToken {
pub fn from_span(kind: LiteralKind, span: Span) -> Self {
assert!(span.text().is_some(), "literal spans must name source text");
Self { kind, span }
}
pub fn new(kind: LiteralKind, text: impl Into<Arc<str>>, span: Span) -> Self {
Self {
kind,
span: span.with_text(text),
}
}
pub fn text(&self) -> &str {
self.span
.text()
.expect("literal tokens must have source-backed spans")
}
}
impl Lex for LiteralToken {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(TokenTree::Literal(self.clone()));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub struct IdentToken {
span: Span,
}
impl IdentToken {
pub fn from_span(span: Span) -> Self {
assert!(
span.text().is_some(),
"identifier spans must name source text"
);
Self { span }
}
pub fn new(text: impl Into<Arc<str>>, span: Span) -> Self {
Self {
span: span.with_text(text),
}
}
pub fn text(&self) -> &str {
self.span
.text()
.expect("identifier tokens must have source-backed spans")
}
}
impl Display for IdentToken {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
formatter.write_str(self.text())
}
}
impl Lex for IdentToken {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(TokenTree::Ident(self.clone()));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Spanned)]
pub struct EocToken {
span: Span,
after_semicolon: bool,
}
impl EocToken {
pub fn new(span: Span) -> Self {
Self {
span,
after_semicolon: false,
}
}
#[doc(hidden)]
pub fn after_semicolon(span: Span) -> Self {
Self {
span,
after_semicolon: true,
}
}
pub fn follows_semicolon(&self) -> bool {
self.after_semicolon
}
}
impl Display for EocToken {
fn fmt(&self, _formatter: &mut Formatter<'_>) -> Result {
Ok(())
}
}
impl Lex for EocToken {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(TokenTree::Eoc(self.clone()));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub struct TokenGroup {
delimiter: Delimiter,
stream: TokenStream,
}
impl TokenGroup {
pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self {
Self { delimiter, stream }
}
pub fn delimiter(&self) -> &Delimiter {
&self.delimiter
}
pub fn delim_kind(&self) -> DelimiterKind {
self.delimiter.kind
}
pub fn stream(&self) -> &TokenStream {
&self.stream
}
pub fn into_stream(self) -> TokenStream {
self.stream
}
}
impl Display for TokenGroup {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
formatter.write_str(self.delim_kind().opening())?;
self.stream.fmt(formatter)?;
if self.delimiter.is_closed() {
formatter.write_str(self.delim_kind().closing())?;
}
Ok(())
}
}
impl Lex for TokenGroup {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(TokenTree::Group(self.clone()));
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TriviaKind {
Whitespace,
CarriageReturn,
LineBreak,
LineComment,
BlockComment,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Spanned)]
pub struct Trivia {
kind: TriviaKind,
span: Span,
}
impl Trivia {
pub fn from_span(kind: TriviaKind, span: Span) -> Self {
assert!(span.text().is_some(), "trivia spans must name source text");
Self { kind, span }
}
pub fn new(kind: TriviaKind, text: impl Into<Arc<str>>, span: Span) -> Self {
Self {
kind,
span: span.with_text(text),
}
}
pub fn kind(&self) -> TriviaKind {
self.kind
}
pub fn text(&self) -> &str {
self.span
.text()
.expect("trivia tokens must have source-backed spans")
}
pub fn contains_line_break(&self) -> bool {
self.text().contains('\n')
}
}
impl Display for Trivia {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
formatter.write_str(self.text())
}
}
impl Lex for Trivia {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(TokenTree::Trivia(self.clone()));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub enum TokenTree {
Eoc(EocToken),
Group(TokenGroup),
Literal(LiteralToken),
Punct(Punct),
Ident(IdentToken),
Trivia(Trivia),
}
impl TokenTree {
pub fn spelling(&self) -> Option<&str> {
match self {
Self::Eoc(_) => None,
Self::Literal(token) => Some(token.text()),
Self::Punct(token) => Some(token.text()),
Self::Ident(token) => Some(token.text()),
Self::Group(_) | Self::Trivia(_) => None,
}
}
pub(crate) fn description(&self) -> String {
match self {
Self::Eoc(_) => "end of cell".into(),
Self::Group(group) => group.delim_kind().to_string(),
Self::Trivia(trivia) => match trivia.kind() {
TriviaKind::Whitespace => "whitespace".into(),
TriviaKind::CarriageReturn => "carriage return".into(),
TriviaKind::LineBreak => "line break".into(),
TriviaKind::LineComment => "line comment".into(),
TriviaKind::BlockComment => "block comment".into(),
},
token => token.spelling().unwrap_or("").to_owned(),
}
}
}
impl Lex for TokenTree {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.push(self.clone());
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Spanned)]
pub struct TokenStream(Vec<TokenTree>);
impl TokenStream {
pub fn new() -> Self {
Self::default()
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &TokenTree> + ExactSizeIterator {
self.0.iter()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub(crate) fn len(&self) -> usize {
self.0.len()
}
pub(crate) fn get(&self, position: usize) -> Option<&TokenTree> {
self.0.get(position)
}
pub(crate) fn last(&self) -> Option<&TokenTree> {
self.0.last()
}
#[doc(hidden)]
pub fn starts_with_whitespace(&self) -> bool {
matches!(self.0.first(), Some(TokenTree::Trivia(_)))
}
#[doc(hidden)]
pub fn ends_with_whitespace(&self) -> bool {
matches!(self.0.last(), Some(TokenTree::Trivia(_)))
}
#[doc(hidden)]
pub fn ends_with_semicolon(&self) -> bool {
matches!(self.0.last(), Some(TokenTree::Punct(token)) if token.text() == ";")
}
#[doc(hidden)]
pub fn mark_final_eoc_after_semicolon(&mut self) {
let Some(TokenTree::Eoc(marker)) = self.0.last_mut() else {
return;
};
*marker = EocToken::after_semicolon(marker.span());
}
#[doc(hidden)]
pub fn append_fragment<T: Lex + ?Sized>(&mut self, fragment: &T) {
let fragment = fragment.to_token_stream();
if self
.last()
.zip(fragment.iter().next())
.is_some_and(|(left, right)| {
(is_wordlike(left) && is_wordlike(right))
|| matches!((left, right), (TokenTree::Punct(left), TokenTree::Punct(right))
if punctuation_would_merge(left.text(), right.text()))
})
{
self.extend([Trivia::new(TriviaKind::Whitespace, " ", Span::detached())]);
}
self.extend([fragment]);
}
pub fn pop(&mut self) -> Option<TokenTree> {
self.0.pop()
}
}
fn is_wordlike(tree: &TokenTree) -> bool {
matches!(
tree,
TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
)
}
impl Display for TokenStream {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
for tree in &self.0 {
match tree {
TokenTree::Group(group) => group.fmt(formatter)?,
TokenTree::Eoc(marker) => marker.fmt(formatter)?,
TokenTree::Literal(literal) => literal.fmt(formatter)?,
TokenTree::Punct(punct) => punct.fmt(formatter)?,
TokenTree::Ident(ident) => ident.fmt(formatter)?,
TokenTree::Trivia(trivia) => trivia.fmt(formatter)?,
}
}
Ok(())
}
}
impl<T: Lex> Extend<T> for TokenStream {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for item in iter {
item.to_tokens(self);
}
}
}
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<T: IntoIterator<Item = TokenTree>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl IntoIterator for TokenStream {
type Item = TokenTree;
type IntoIter = IntoIter<TokenTree>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Lex for TokenStream {
fn to_tokens(&self, output: &mut TokenStream) {
output.0.extend(self.0.iter().cloned());
}
}
pub trait Lex {
fn to_tokens(&self, output: &mut TokenStream);
fn to_token_stream(&self) -> TokenStream {
let mut output = TokenStream::new();
self.to_tokens(&mut output);
output
}
fn to_m2(&self) -> String {
self.to_token_stream().to_string()
}
}
impl<T: Lex + ?Sized> Lex for &T {
fn to_tokens(&self, output: &mut TokenStream) {
(*self).to_tokens(output);
}
}
impl<T: Lex + ?Sized> Lex for Box<T> {
fn to_tokens(&self, output: &mut TokenStream) {
self.as_ref().to_tokens(output);
}
}
impl<T: Lex> Lex for Option<T> {
fn to_tokens(&self, output: &mut TokenStream) {
if let Some(value) = self {
value.to_tokens(output);
}
}
}
impl<T: Lex> Lex for [T] {
fn to_tokens(&self, output: &mut TokenStream) {
for token in self {
token.to_tokens(output);
}
}
}
impl<T: Lex> Lex for Vec<T> {
fn to_tokens(&self, output: &mut TokenStream) {
self.as_slice().to_tokens(output);
}
}