use rucc_ast::{Designator, DesignatorList, Init, InitId, InitItem, InitItemList};
use rucc_lex::Punct;
use crate::parser::Parser;
impl Parser<'_> {
pub(crate) fn initializer(&mut self) -> InitId {
if self.cursor.at_punct(Punct::LBrace) {
return self.braced_init();
}
self.assign_init()
}
pub(crate) fn assign_init(&mut self) -> InitId {
let value = self.assign_expr();
self.ast.add_init(Init::Expr(value))
}
pub(crate) fn braced_init(&mut self) -> InitId {
if !self.enter() {
self.cursor.bump();
return self.ast.add_init(Init::List(InitItemList::EMPTY));
}
self.cursor.bump();
let mut items = Vec::new();
while !self.cursor.at_punct(Punct::RBrace) && !self.cursor.is_eof() {
let at = self.cursor.span();
let before = self.cursor.index();
let designators = self.designation();
let init = self.initializer();
items.push(InitItem { designators, init, span: self.span_from(at) });
if !self.cursor.eat_punct(Punct::Comma) {
break;
}
if self.cursor.index() == before {
break;
}
}
self.expect_punct(Punct::RBrace);
self.leave();
let items = self.ast.add_init_item_list(&items);
self.ast.add_init(Init::List(items))
}
fn designation(&mut self) -> DesignatorList {
if let Some(name) = self.cursor.current().ident() {
if self.cursor.peek(1).punct() == Some(Punct::Colon) {
let at = self.cursor.span();
self.pedantic("E0413", "obsolete designator, write `.field =` instead", at);
self.cursor.bump();
self.cursor.bump();
return self.ast.add_designator_list(&[Designator::ObsoleteField(name)]);
}
}
let mut out = Vec::new();
loop {
if self.cursor.eat_punct(Punct::Dot) {
match self.expect_ident() {
Some((name, _)) => out.push(Designator::Field(name)),
None => break,
}
} else if self.cursor.at_punct(Punct::LBracket) {
if !self.enter() {
self.cursor.bump();
break;
}
self.cursor.bump();
let lo = self.const_expr();
let designator = if self.cursor.eat_punct(Punct::Ellipsis) {
Designator::Range { lo, hi: self.const_expr() }
} else {
Designator::Index(lo)
};
self.expect_punct(Punct::RBracket);
self.leave();
out.push(designator);
} else {
break;
}
}
if out.is_empty() {
return DesignatorList::EMPTY;
}
self.expect_punct(Punct::Eq);
self.ast.add_designator_list(&out)
}
}