From 40feacdeb90786b49ea9e0510ba22ff7af79e020 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 31 Jan 2019 21:09:43 +0300 Subject: split macros across crates --- crates/ra_mbe/src/mbe_parser.rs | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 crates/ra_mbe/src/mbe_parser.rs (limited to 'crates/ra_mbe/src/mbe_parser.rs') diff --git a/crates/ra_mbe/src/mbe_parser.rs b/crates/ra_mbe/src/mbe_parser.rs new file mode 100644 index 000000000..a70ed1d52 --- /dev/null +++ b/crates/ra_mbe/src/mbe_parser.rs @@ -0,0 +1,93 @@ +use crate::{self as mbe, tt_cursor::TtCursor}; + +/// This module parses a raw `tt::TokenStream` into macro-by-example token +/// stream. This is a *mostly* identify function, expect for handling of +/// `$var:tt_kind` and `$(repeat),*` constructs. + +pub fn parse(tt: &tt::Subtree) -> Option { + let mut parser = TtCursor::new(tt); + let mut rules = Vec::new(); + while !parser.is_eof() { + rules.push(parse_rule(&mut parser)?) + } + Some(mbe::MacroRules { rules }) +} + +fn parse_rule(p: &mut TtCursor) -> Option { + let lhs = parse_subtree(p.eat_subtree()?)?; + p.expect_char('=')?; + p.expect_char('>')?; + let rhs = parse_subtree(p.eat_subtree()?)?; + Some(mbe::Rule { lhs, rhs }) +} + +fn parse_subtree(tt: &tt::Subtree) -> Option { + let mut token_trees = Vec::new(); + let mut p = TtCursor::new(tt); + while let Some(tt) = p.eat() { + let child: mbe::TokenTree = match tt { + tt::TokenTree::Leaf(leaf) => match leaf { + tt::Leaf::Punct(tt::Punct { char: '$', .. }) => { + if p.at_ident().is_some() { + mbe::Leaf::from(parse_var(&mut p)?).into() + } else { + parse_repeat(&mut p)?.into() + } + } + tt::Leaf::Punct(punct) => mbe::Leaf::from(*punct).into(), + tt::Leaf::Ident(tt::Ident { text }) => { + mbe::Leaf::from(mbe::Ident { text: text.clone() }).into() + } + tt::Leaf::Literal(tt::Literal { text }) => { + mbe::Leaf::from(mbe::Literal { text: text.clone() }).into() + } + }, + tt::TokenTree::Subtree(subtree) => parse_subtree(&subtree)?.into(), + }; + token_trees.push(child); + } + Some(mbe::Subtree { + token_trees, + delimiter: tt.delimiter, + }) +} + +fn parse_var(p: &mut TtCursor) -> Option { + let ident = p.eat_ident().unwrap(); + let text = ident.text.clone(); + let kind = if p.at_char(':') { + p.bump(); + if let Some(ident) = p.eat_ident() { + Some(ident.text.clone()) + } else { + p.rev_bump(); + None + } + } else { + None + }; + Some(mbe::Var { text, kind }) +} + +fn parse_repeat(p: &mut TtCursor) -> Option { + let subtree = p.eat_subtree().unwrap(); + let subtree = parse_subtree(subtree)?; + let sep = p.eat_punct()?; + let (separator, rep) = match sep.char { + '*' | '+' | '?' => (None, sep.char), + char => (Some(char), p.eat_punct()?.char), + }; + + let kind = match rep { + '*' => mbe::RepeatKind::ZeroOrMore, + '+' => mbe::RepeatKind::OneOrMore, + '?' => mbe::RepeatKind::ZeroOrOne, + _ => return None, + }; + p.bump(); + Some(mbe::Repeat { + subtree, + kind, + separator, + }) +} -- cgit v1.2.3