use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use std::cell::{Cell,RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use crate::{
token::{ExpandToken, Token, TokenIter},
ScopeMode,
};
const PRODUCT_CHAR: char = '$';
#[cfg_attr(feature = "debug", derive(Debug))]
#[derive(Clone)]
pub(crate) struct Product(Rc<ProductInner>);
impl From<ProductInner> for Product {
fn from(inner: ProductInner) -> Self {
Self(Rc::new(inner))
}
}
#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct ProductInner {
parent: RefCell<Parent>,
entries: RefCell<Vec<Token>>,
input: RefCell<TokenIter>,
products: RefCell<Vec<Vec<TokenStream>>>,
name_lookup: RefCell<HashMap<String, usize>>,
linear_scope: Cell<bool>
}
impl Product {
pub fn new(input: TokenStream) -> Self {
ProductInner {
parent: RefCell::new(Parent::Root(TokenStream::new())),
entries: RefCell::new(Vec::new()),
input: RefCell::new(TokenIter::new(input)),
products: RefCell::new(Vec::new()),
name_lookup: RefCell::new(HashMap::new()),
linear_scope: Cell::new(false),
}
.into()
}
pub fn new_product_scope(parent: &Product, input: TokenStream) -> Self {
ProductInner {
parent: RefCell::new(Parent::ParentScope(parent.clone())),
entries: RefCell::new(Vec::new()),
input: RefCell::new(TokenIter::new(input)),
products: RefCell::new(Vec::new()),
name_lookup: RefCell::new(HashMap::new()),
linear_scope: Cell::new(false),
}
.into()
}
pub fn new_linear_scope(parent: &Product, input: TokenStream) -> Self {
ProductInner {
parent: RefCell::new(Parent::ParentScope(parent.clone())),
entries: RefCell::new(Vec::new()),
input: RefCell::new(TokenIter::new(input)),
products: RefCell::new(Vec::new()),
name_lookup: RefCell::new(HashMap::new()),
linear_scope: Cell::new(true),
}
.into()
}
fn sub_group<F: FnOnce(&Self)>(&self, group: Group, recurse: F) {
let delim = group.delimiter();
let old_iter = std::mem::replace(
&mut *self.0.input.borrow_mut(),
TokenIter::new(group.stream()),
);
let old_entries = std::mem::take(&mut *self.0.entries.borrow_mut());
recurse(self);
let rec_entries = std::mem::replace(&mut *self.0.entries.borrow_mut(), old_entries);
let new_group = Token::from_group(delim, rec_entries);
self.push(new_group);
_ = std::mem::replace(&mut *self.0.input.borrow_mut(), old_iter);
}
}
impl Product {
pub fn parse(self, mode: ScopeMode) -> Self {
match mode {
ScopeMode::Expand => self.parse_toplevel(),
ScopeMode::SubExpand => self.parse_toplevel_noexpand(),
ScopeMode::AutoBraceSemi => self.parse_toplevel_auto_bracesemi(),
}
self
}
}
impl Product {
fn push(&self, entry: Token) {
self.0.entries.borrow_mut().push(entry);
}
fn push_token(&self, token: TokenTree) {
self.push(Token::from_tokentree(token));
}
}
impl Product {
pub fn parse_toplevel(&self) {
while self.0.input.borrow().token_available() {
let _ = self.parse_product_entity() || self.parse_group() || self.parse_rust();
}
}
pub fn parse_toplevel_noexpand(&self) {
while self.0.input.borrow().token_available() {
let _ = self.parse_product_entity_noexpand()
|| self.parse_group_noexpand()
|| self.parse_rust();
}
}
pub fn parse_toplevel_auto_bracesemi(&self) {
while self.0.input.borrow().token_available() {
let _ = self.parse_product_entity()
|| self.parse_bracesemi()
|| self.parse_group()
|| self.parse_rust();
}
}
fn parse_rust(&self) -> bool {
self.push_token(self.0.input.borrow().next_token());
true
}
fn parse_product_char(&self) -> bool {
self.0.input.borrow().next_punct_with(PRODUCT_CHAR)
}
fn parse_product_entity(&self) -> bool {
self.parse_product_char()
&& (self.parse_scope()
|| self.parse_product_definition()
|| self.parse_product_reference()
|| self.parse_rust())
}
fn parse_bracesemi(&self) -> bool {
if self.parse_brace() || self.parse_semicolon() {
self.auto_expand_cycle();
true
} else {
false
}
}
fn parse_brace(&self) -> bool {
let group = self.0.input.borrow().next_group_with(Delimiter::Brace);
if let Some(group) = group {
self.sub_group(group, |s| {
s.parse_toplevel();
});
true
} else {
false
}
}
fn parse_semicolon(&self) -> bool {
if self.0.input.borrow().next_punct_with(';') {
self.push_token(TokenTree::Punct(Punct::new(';', Spacing::Alone)));
true
} else {
false
}
}
fn parse_group(&self) -> bool {
let group = self.0.input.borrow().next_group();
if let Some(group) = group {
self.sub_group(group, |s| {
s.parse_toplevel();
});
true
} else {
false
}
}
fn parse_product_entity_noexpand(&self) -> bool {
self.parse_product_char()
&& (self.parse_scope() || {
self.push_token(TokenTree::Punct(Punct::new(PRODUCT_CHAR, Spacing::Alone)));
true
})
}
fn parse_group_noexpand(&self) -> bool {
let group = self.0.input.borrow().next_group();
if let Some(group) = group {
self.sub_group(group, |s| {
s.parse_toplevel_noexpand();
});
true
} else {
false
}
}
fn parse_scope(&self) -> bool {
self.parse_product_scope() | self.parse_linear_scope()
}
fn parse_product_scope(&self) -> bool {
if let Some(group) = self.0.input.borrow().next_group_with(Delimiter::Brace) {
let scope = Product::new_product_scope(self, group.stream());
scope.parse(ScopeMode::Expand).expand_scope();
true
} else {
false
}
}
fn parse_linear_scope(&self) -> bool {
if let Some(group) = self.0.input.borrow().next_group_with(Delimiter::Bracket) {
let scope = Product::new_linear_scope(self, group.stream());
scope.parse(ScopeMode::Expand).expand_scope();
true
} else {
false
}
}
fn parse_product_definition(&self) -> bool {
if let Some(group) = self
.0
.input
.borrow()
.next_group_with(Delimiter::Parenthesis)
{
let group = TokenIter::new(group.stream());
let mut visible = group.next_punct_with(PRODUCT_CHAR);
let name = if let Some(TokenTree::Ident(i)) = group.peek() {
group.next();
assert!(
group.next_punct_with(':'),
"expected ':' after product name"
);
Some(i.to_string())
} else {
None
};
let mut products = Vec::new();
if group.peek_group_with(Delimiter::Parenthesis) {
while let Some(group) = group.next_group_with(Delimiter::Parenthesis) {
products.push(group.stream());
}
assert!(
!group.token_available(),
"expected multiple product definitions to be parenthesized"
);
} else {
products.push(group.stream());
}
let mut defs = self.0.products.borrow_mut();
defs.push(products);
let index = defs.len() - 1;
if let Some(name) = name {
if self
.0
.name_lookup
.borrow_mut()
.insert(name, index)
.is_some()
{
panic!("Key redefined");
}
} else {
visible = true
}
if visible {
self.push(Token::IndexedReference(index));
}
true
} else {
false
}
}
fn parse_product_reference(&self) -> bool {
if let Some(ident) = self.0.input.borrow().next_ident() {
let name = ident.to_string();
if let Some(local) = self.0.name_lookup.borrow().get(name.as_str()) {
self.push(Token::IndexedReference(*local));
return true;
} else {
fn name_in_parent(product: &Product, name: &str) -> bool {
let parent = product.0.parent.borrow();
match *parent {
Parent::Root(_) => false,
Parent::ParentScope(ref parent) => {
if parent.0.name_lookup.borrow().contains_key(name) {
true
} else {
name_in_parent(parent, name)
}
}
}
}
if !name_in_parent(self, name.as_str()) {
panic!("undefined reference {}", name);
}
}
self.push(Token::NamedReference(name));
true
} else if let Some(literal) = self.0.input.borrow().next_literal() {
let index = literal
.to_string()
.parse::<usize>()
.expect("expected numeric reference");
assert!(
index < self.0.products.borrow().len(),
"undefined reference {}",
index
);
self.push(Token::IndexedReference(index));
true
} else {
false
}
}
}
impl Product {
pub fn expand(self) -> TokenStream {
self.expand_scope();
let Parent::Root(ts) = Rc::into_inner(self.0).unwrap().parent.into_inner() else {
panic!("can only expand() a top level scope")
};
ts
}
fn auto_expand_cycle(&self) {
self.expand_scope();
self.0.entries.borrow_mut().clear();
self.0.products.borrow_mut().clear();
self.0.name_lookup.borrow_mut().clear();
}
fn expand_scope(&self) {
if self.0.linear_scope.get() {
self.expand_linear_scope();
} else {
self.expand_product_scope();
}
}
fn expand_product_scope(&self) {
let permutations = {
let mut permutations = vec![vec![]];
for defs in self.0.products.borrow().iter() {
let mut tmp = Vec::new();
for item in defs {
for perm in &permutations {
let mut new_perm = perm.clone();
new_perm.push(item.clone());
tmp.push(new_perm);
}
}
permutations = tmp;
}
permutations
};
let mut parent = self.0.parent.borrow_mut();
match &mut *parent {
Parent::Root(ref mut stream) => {
for perms in permutations {
for token in self.0.entries.borrow().iter() {
stream.expand_token(token, &perms);
}
}
}
Parent::ParentScope(parent) => {
for perms in permutations {
for token in self.0.entries.borrow().iter() {
parent.0.entries.borrow_mut().expand_token(token, &perms);
}
}
}
}
}
fn expand_linear_scope(&self) {
let definitions = self.0.products.borrow();
let len = if !definitions.is_empty() {
let len = definitions[0].len();
for def in definitions.iter().skip(1) {
assert_eq!(
len,
def.len(),
"linear scope definitions must have the same number of elements"
);
}
len
} else {
0
};
for i in 0..(len.max(1)) {
let defs = definitions.iter().map(|d| d[i].clone()).collect::<Vec<_>>();
let mut parent = self.0.parent.borrow_mut();
match &mut *parent {
Parent::Root(ref mut stream) => {
for token in self.0.entries.borrow().iter() {
stream.expand_token(token, &defs);
}
}
Parent::ParentScope(parent) => {
for token in self.0.entries.borrow().iter() {
parent.0.entries.borrow_mut().expand_token(token, &defs);
}
}
}
}
}
}
#[cfg_attr(feature = "debug", derive(Debug))]
enum Parent {
Root(TokenStream),
ParentScope(Product),
}