Make use of SpanRange instead of Span

This commit is contained in:
CreepySkeleton 2020-08-31 11:57:55 +03:00
parent ef120ab2d0
commit 7d16af9a06
3 changed files with 82 additions and 89 deletions

View file

@ -1,18 +1,19 @@
use proc_macro2::{Span, TokenStream, TokenTree};
use proc_macro2::{TokenStream, TokenTree};
use proc_macro_error::SpanRange;
#[derive(Debug)]
pub enum Markup {
Block(Block),
Literal {
content: String,
span: Span,
span: SpanRange,
},
Symbol {
symbol: TokenStream,
},
Splice {
expr: TokenStream,
outer_span: Span,
outer_span: SpanRange,
},
Element {
name: TokenStream,
@ -20,22 +21,22 @@ pub enum Markup {
body: ElementBody,
},
Let {
at_span: Span,
at_span: SpanRange,
tokens: TokenStream,
},
Special {
segments: Vec<Special>,
},
Match {
at_span: Span,
at_span: SpanRange,
head: TokenStream,
arms: Vec<MatchArm>,
arms_span: Span,
arms_span: SpanRange,
},
}
impl Markup {
pub fn span(&self) -> Span {
pub fn span(&self) -> SpanRange {
match *self {
Markup::Block(ref block) => block.span(),
Markup::Literal { span, .. } => span,
@ -43,16 +44,16 @@ impl Markup {
Markup::Splice { outer_span, .. } => outer_span,
Markup::Element { ref name, ref body, .. } => {
let name_span = span_tokens(name.clone());
name_span.join(body.span()).unwrap_or(name_span)
name_span.join_range(body.span())
},
Markup::Let { at_span, ref tokens } => {
at_span.join(span_tokens(tokens.clone())).unwrap_or(at_span)
at_span.join_range(span_tokens(tokens.clone()))
},
Markup::Special { ref segments } => {
join_spans(segments.iter().map(Special::span))
join_ranges(segments.iter().map(Special::span))
},
Markup::Match { at_span, arms_span, .. } => {
at_span.join(arms_span).unwrap_or(at_span)
at_span.join_range(arms_span)
},
}
}
@ -63,12 +64,12 @@ pub type Attrs = Vec<Attr>;
#[derive(Debug)]
pub enum Attr {
Class {
dot_span: Span,
dot_span: SpanRange,
name: Markup,
toggler: Option<Toggler>,
},
Id {
hash_span: Span,
hash_span: SpanRange,
name: Markup,
},
Attribute {
@ -77,20 +78,20 @@ pub enum Attr {
}
impl Attr {
pub fn span(&self) -> Span {
pub fn span(&self) -> SpanRange {
match *self {
Attr::Class { dot_span, ref name, ref toggler } => {
let name_span = name.span();
let dot_name_span = dot_span.join(name_span).unwrap_or(dot_span);
let dot_name_span = dot_span.join_range(name_span);
if let Some(toggler) = toggler {
dot_name_span.join(toggler.cond_span).unwrap_or(name_span)
dot_name_span.join_range(toggler.cond_span)
} else {
dot_name_span
}
},
Attr::Id { hash_span, ref name } => {
let name_span = name.span();
hash_span.join(name_span).unwrap_or(hash_span)
hash_span.join_range(name_span)
},
Attr::Attribute { ref attribute } => attribute.span(),
}
@ -99,12 +100,12 @@ impl Attr {
#[derive(Debug)]
pub enum ElementBody {
Void { semi_span: Span },
Void { semi_span: SpanRange },
Block { block: Block },
}
impl ElementBody {
pub fn span(&self) -> Span {
pub fn span(&self) -> SpanRange {
match *self {
ElementBody::Void { semi_span } => semi_span,
ElementBody::Block { ref block } => block.span(),
@ -115,26 +116,26 @@ impl ElementBody {
#[derive(Debug)]
pub struct Block {
pub markups: Vec<Markup>,
pub outer_span: Span,
pub outer_span: SpanRange,
}
impl Block {
pub fn span(&self) -> Span {
pub fn span(&self) -> SpanRange {
self.outer_span
}
}
#[derive(Debug)]
pub struct Special {
pub at_span: Span,
pub at_span: SpanRange,
pub head: TokenStream,
pub body: Block,
}
impl Special {
pub fn span(&self) -> Span {
pub fn span(&self) -> SpanRange {
let body_span = self.body.span();
self.at_span.join(body_span).unwrap_or(self.at_span)
self.at_span.join_range(body_span)
}
}
@ -145,10 +146,10 @@ pub struct Attribute {
}
impl Attribute {
fn span(&self) -> Span {
fn span(&self) -> SpanRange {
let name_span = span_tokens(self.name.clone());
if let Some(attr_type_span) = self.attr_type.span() {
name_span.join(attr_type_span).unwrap_or(name_span)
name_span.join_range(attr_type_span)
} else {
name_span
}
@ -166,7 +167,7 @@ pub enum AttrType {
}
impl AttrType {
fn span(&self) -> Option<Span> {
fn span(&self) -> Option<SpanRange> {
match *self {
AttrType::Normal { ref value } => Some(value.span()),
AttrType::Empty { ref toggler } => toggler.as_ref().map(Toggler::span),
@ -177,11 +178,11 @@ impl AttrType {
#[derive(Debug)]
pub struct Toggler {
pub cond: TokenStream,
pub cond_span: Span,
pub cond_span: SpanRange,
}
impl Toggler {
fn span(&self) -> Span {
fn span(&self) -> SpanRange {
self.cond_span
}
}
@ -192,20 +193,16 @@ pub struct MatchArm {
pub body: Block,
}
pub fn span_tokens<I: IntoIterator<Item=TokenTree>>(tokens: I) -> Span {
join_spans(tokens.into_iter().map(|token| token.span()))
pub fn span_tokens<I: IntoIterator<Item=TokenTree>>(tokens: I) -> SpanRange {
join_ranges(tokens.into_iter().map(|s| SpanRange::single_span(s.span())))
}
pub fn join_spans<I: IntoIterator<Item=Span>>(spans: I) -> Span {
let mut iter = spans.into_iter();
let mut span = match iter.next() {
pub fn join_ranges<I: IntoIterator<Item=SpanRange>>(ranges: I) -> SpanRange {
let mut iter = ranges.into_iter();
let first = match iter.next() {
Some(span) => span,
None => return Span::call_site(),
None => return SpanRange::call_site(),
};
for new_span in iter {
if let Some(joined) = span.join(new_span) {
span = joined;
}
}
span
let last = iter.last().unwrap_or(first);
first.join_range(last)
}

View file

@ -9,6 +9,7 @@ use proc_macro2::{
TokenTree,
};
use quote::quote;
use proc_macro_error::SpanRange;
use crate::ast::*;
@ -63,7 +64,7 @@ impl Generator {
.map(|arm| self.match_arm(arm))
.collect();
let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body));
body.set_span(arms_span.into());
body.set_span(arms_span.collapse());
let head: TokenStream = head.into();
quote!(#head #body)
});
@ -75,7 +76,7 @@ impl Generator {
let mut build = self.builder();
self.markups(markups, &mut build);
let mut block = TokenTree::Group(Group::new(Delimiter::Brace, build.finish()));
block.set_span(outer_span.into());
block.set_span(outer_span.collapse());
TokenStream::from(block)
}
@ -203,7 +204,7 @@ fn desugar_classes_or_ids(
};
let head = desugar_toggler(toggler);
markups.push(Markup::Special {
segments: vec![Special { at_span: Span::call_site(), head: head.into(), body }],
segments: vec![Special { at_span: SpanRange::call_site(), head: head.into(), body }],
});
}
Some(Attribute {
@ -211,7 +212,7 @@ fn desugar_classes_or_ids(
attr_type: AttrType::Normal {
value: Markup::Block(Block {
markups,
outer_span: Span::call_site(),
outer_span: SpanRange::call_site(),
}),
},
})
@ -236,7 +237,7 @@ fn desugar_toggler(Toggler { cond, cond_span }: Toggler) -> TokenStream {
// wrap it in parentheses to avoid parse errors
if cond.clone().into_iter().any(is_braced_block) {
let mut wrapped_cond = TokenTree::Group(Group::new(Delimiter::Parenthesis, cond));
wrapped_cond.set_span(cond_span.into());
wrapped_cond.set_span(cond_span.collapse());
cond = TokenStream::from(wrapped_cond);
}
quote!(if #cond)

View file

@ -7,7 +7,7 @@ use proc_macro2::{
TokenStream,
TokenTree,
};
use proc_macro_error::{abort, abort_call_site};
use proc_macro_error::{abort, abort_call_site, SpanRange};
use std::collections::HashMap;
use std::mem;
@ -128,13 +128,11 @@ impl Parser {
"for" => self.for_expr(at_span, keyword),
"match" => self.match_expr(at_span, keyword),
"let" => {
let ident_span = ident.span();
let span = at_span.join(ident_span).unwrap_or(ident_span);
let span = SpanRange { first: at_span, last: ident.span() };
abort!(span, "`@let` only works inside a block");
},
other => {
let ident_span = ident.span();
let span = at_span.join(ident_span).unwrap_or(ident_span);
let span = SpanRange { first: at_span, last: ident.span() };
abort!(span, "unknown keyword `@{}`", other);
}
}
@ -146,7 +144,7 @@ impl Parser {
},
// Element
TokenTree::Ident(ident) => {
let ident_string = ident.to_string();
let _ident_string = ident.to_string();
// Is this a keyword that's missing a '@'?
// TODO: warning or error?
// match ident_string.as_str() {
@ -171,12 +169,12 @@ impl Parser {
// Splice
TokenTree::Group(ref group) if group.delimiter() == Delimiter::Parenthesis => {
self.advance();
ast::Markup::Splice { expr: group.stream(), outer_span: group.span() }
ast::Markup::Splice { expr: group.stream(), outer_span: SpanRange::single_span(group.span()) }
}
// Block
TokenTree::Group(ref group) if group.delimiter() == Delimiter::Brace => {
self.advance();
ast::Markup::Block(self.block(group.stream(), group.span()))
ast::Markup::Block(self.block(group.stream(), SpanRange::single_span(group.span())))
},
// ???
token => {
@ -193,7 +191,7 @@ impl Parser {
.unwrap_or_else(|_| abort!(lit, "expected string"));
ast::Markup::Literal {
content,
span: lit.span(),
span: SpanRange::single_span(lit.span()),
}
}
@ -210,18 +208,18 @@ impl Parser {
let body = loop {
match self.next() {
Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => {
break self.block(block.stream(), block.span());
break self.block(block.stream(), SpanRange::single_span(block.span()));
},
Some(token) => head.push(token),
None => {
let head_span = ast::span_tokens(head);
let span = at_span.join(head_span).unwrap_or(head_span);
let mut span = ast::span_tokens(head);
span.first = at_span;
abort!(span, "expected body for this `@if`");
},
}
};
segments.push(ast::Special {
at_span,
at_span: SpanRange::single_span(at_span),
head: head.into_iter().collect(),
body,
});
@ -251,16 +249,15 @@ impl Parser {
_ => {
match self.next() {
Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Brace => {
let body = self.block(group.stream(), group.span());
let body = self.block(group.stream(), SpanRange::single_span(group.span()));
segments.push(ast::Special {
at_span,
at_span: SpanRange::single_span(at_span),
head: vec![else_keyword].into_iter().collect(),
body,
});
},
_ => {
let else_span = else_keyword.span();
let span = at_span.join(else_span).unwrap_or(else_span);
let span = SpanRange { first: at_span, last: else_keyword.span() };
abort!(span, "expected body for this `@else`");
},
}
@ -281,17 +278,17 @@ impl Parser {
let body = loop {
match self.next() {
Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => {
break self.block(block.stream(), block.span());
break self.block(block.stream(), SpanRange::single_span(block.span()));
},
Some(token) => head.push(token),
None => {
let span = at_span.join(keyword_span).unwrap_or(keyword_span);
let span = SpanRange { first: at_span, last: keyword_span };
abort!(span, "expected body for this `@while`");
},
}
};
ast::Markup::Special {
segments: vec![ast::Special { at_span, head: head.into_iter().collect(), body }],
segments: vec![ast::Special { at_span: SpanRange::single_span(at_span), head: head.into_iter().collect(), body }],
}
}
@ -309,7 +306,7 @@ impl Parser {
},
Some(token) => head.push(token),
None => {
let span = at_span.join(keyword_span).unwrap_or(keyword_span);
let span = SpanRange { first: at_span, last: keyword_span };
abort!(span, "missing `in` in `@for` loop");
},
}
@ -317,17 +314,17 @@ impl Parser {
let body = loop {
match self.next() {
Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => {
break self.block(block.stream(), block.span());
break self.block(block.stream(), SpanRange::single_span(block.span()));
},
Some(token) => head.push(token),
None => {
let span = at_span.join(keyword_span).unwrap_or(keyword_span);
let span = SpanRange { first: at_span, last: keyword_span };
abort!(span, "expected body for this `@for`");
},
}
};
ast::Markup::Special {
segments: vec![ast::Special { at_span, head: head.into_iter().collect(), body }],
segments: vec![ast::Special { at_span: SpanRange::single_span(at_span), head: head.into_iter().collect(), body }],
}
}
@ -340,17 +337,17 @@ impl Parser {
let (arms, arms_span) = loop {
match self.next() {
Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => {
let span = body.span();
let span = SpanRange::single_span(body.span());
break (self.with_input(body.stream()).match_arms(), span);
},
Some(token) => head.push(token),
None => {
let span = at_span.join(keyword_span).unwrap_or(keyword_span);
let span = SpanRange { first: at_span, last: keyword_span };
abort!(span, "expected body for this `@match`");
},
}
};
ast::Markup::Match { at_span, head: head.into_iter().collect(), arms, arms_span }
ast::Markup::Match { at_span: SpanRange::single_span(at_span), head: head.into_iter().collect(), arms, arms_span }
}
fn match_arms(&mut self) -> Vec<ast::MatchArm> {
@ -389,7 +386,7 @@ impl Parser {
let body = match self.next() {
// $pat => { $stmts }
Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => {
let body = self.block(body.stream(), body.span());
let body = self.block(body.stream(), SpanRange::single_span(body.span()));
// Trailing commas are optional if the match arm is a braced block
if let Some(TokenTree::Punct(ref punct)) = self.peek() {
if punct.as_char() == ',' {
@ -400,15 +397,13 @@ impl Parser {
},
// $pat => $expr
Some(first_token) => {
let mut span = first_token.span();
let mut span = SpanRange::single_span(first_token.span());
let mut body = vec![first_token];
loop {
match self.next() {
Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => break,
Some(token) => {
if let Some(bigger_span) = span.join(token.span()) {
span = bigger_span;
}
span.last = token.span();
body.push(token);
},
None => break,
@ -441,8 +436,8 @@ impl Parser {
}
},
None => {
let tokens_span = ast::span_tokens(tokens);
let span = at_span.join(tokens_span).unwrap_or(tokens_span);
let mut span = ast::span_tokens(tokens);
span.first = at_span;
abort!(span, "unexpected end of `@let` expression");
}
}
@ -459,8 +454,8 @@ impl Parser {
}
},
None => {
let tokens_span = ast::span_tokens(tokens);
let span = at_span.join(tokens_span).unwrap_or(tokens_span);
let mut span = ast::span_tokens(tokens);
span.first = at_span;
abort!(
span,
"unexpected end of `@let` expression";
@ -469,7 +464,7 @@ impl Parser {
},
}
}
ast::Markup::Let { at_span, tokens: tokens.into_iter().collect() }
ast::Markup::Let { at_span: SpanRange::single_span(at_span), tokens: tokens.into_iter().collect() }
}
/// Parses an element node.
@ -486,7 +481,7 @@ impl Parser {
if punct.as_char() == ';' || punct.as_char() == '/' => {
// Void element
self.advance();
ast::ElementBody::Void { semi_span: punct.span() }
ast::ElementBody::Void { semi_span: SpanRange::single_span(punct.span()) }
},
_ => {
match self.markup() {
@ -546,20 +541,20 @@ impl Parser {
self.commit(attempt);
let name = self.class_or_id_name();
let toggler = self.attr_toggler();
attrs.push(ast::Attr::Class { dot_span: punct.span(), name, toggler });
attrs.push(ast::Attr::Class { dot_span: SpanRange::single_span(punct.span()), name, toggler });
},
// ID shorthand
(None, Some(TokenTree::Punct(ref punct))) if punct.as_char() == '#' => {
self.commit(attempt);
let name = self.class_or_id_name();
attrs.push(ast::Attr::Id { hash_span: punct.span(), name });
attrs.push(ast::Attr::Id { hash_span: SpanRange::single_span(punct.span()), name });
},
// If it's not a valid attribute, backtrack and bail out
_ => break,
}
}
let mut attr_map: HashMap<String, Vec<Span>> = HashMap::new();
let mut attr_map: HashMap<String, Vec<SpanRange>> = HashMap::new();
let mut has_class = false;
for attr in &attrs {
let name = match attr {
@ -607,7 +602,7 @@ impl Parser {
self.advance();
Some(ast::Toggler {
cond: group.stream(),
cond_span: group.span(),
cond_span: SpanRange::single_span(group.span()),
})
},
_ => None,
@ -657,7 +652,7 @@ impl Parser {
}
/// Parses the given token stream as a Maud expression.
fn block(&mut self, body: TokenStream, outer_span: Span) -> ast::Block {
fn block(&mut self, body: TokenStream, outer_span: SpanRange) -> ast::Block {
let markups = self.with_input(body).markups();
ast::Block { markups, outer_span }
}