use rucc_ast::{
ArraySize, AttrList, Declarator, DeclaratorId, Derived, DerivedList, MAX_DECLARATOR_DEPTH,
Param, ParamKind, ParamList, Quals, TypeName, TypeNameId,
};
use rucc_lex::{Keyword, Punct};
use crate::parser::Parser;
use crate::scope::IdentKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum DeclKind {
Concrete,
Abstract,
Either,
}
impl Parser<'_> {
pub(crate) fn declarator(&mut self) -> DeclaratorId {
self.any_declarator(DeclKind::Concrete)
}
pub(crate) fn type_name(&mut self) -> TypeNameId {
let start = self.cursor.span();
let before = self.cursor.index();
let specs = self.decl_specs();
if self.cursor.index() == before {
let found = self.describe(self.cursor.current());
self.error("E0407", format!("expected a type name, found {found}"), start);
}
let declarator = self.any_declarator(DeclKind::Abstract);
let span = self.span_from(start);
self.ast.add_type_name(TypeName { specs, declarator, span })
}
pub(crate) fn any_declarator(&mut self, kind: DeclKind) -> DeclaratorId {
let start = self.cursor.span();
let mut outer: Vec<Vec<Derived>> = Vec::new();
let mut pointers = self.pointers();
let mut name = None;
let mut name_span = self.cursor.prev_end();
loop {
if self.at_grouping_paren(kind) {
if outer.len() >= MAX_DECLARATOR_DEPTH || !self.enter() {
self.declarator_too_deep();
break;
}
self.cursor.bump();
outer.push(pointers);
pointers = self.pointers();
continue;
}
if let Some(symbol) = self.cursor.current().ident() {
if kind != DeclKind::Abstract {
name = Some(symbol);
name_span = self.cursor.span();
self.cursor.bump();
}
} else if kind == DeclKind::Concrete {
let found = self.describe(self.cursor.current());
let at = self.cursor.span();
self.error("E0401", format!("expected a name, found {found}"), at);
}
break;
}
let mut derived = Vec::new();
loop {
self.declarator_suffixes(&mut derived);
derived.extend(pointers.iter().rev().copied());
match outer.pop() {
Some(enclosing) => {
self.expect_punct(Punct::RParen);
self.leave();
pointers = enclosing;
}
None => break,
}
}
let derived = self.ast.add_derived_list(&derived);
let span = self.span_from(start);
self.ast.add_declarator(Declarator { name, name_span, derived, span })
}
fn declarator_too_deep(&mut self) {
let at = self.cursor.span();
let message = format!("declarator nested more deeply than {MAX_DECLARATOR_DEPTH} levels");
self.error("E0410", message, at);
}
fn at_grouping_paren(&self, kind: DeclKind) -> bool {
if !self.cursor.at_punct(Punct::LParen) {
return false;
}
let next = self.cursor.peek(1);
if next.punct() == Some(Punct::RParen) || next.punct() == Some(Punct::Ellipsis) {
return false;
}
if self.starts_decl_specs(next) {
return false;
}
if kind == DeclKind::Abstract && next.ident().is_some() {
return false;
}
true
}
fn pointers(&mut self) -> Vec<Derived> {
let mut out = Vec::new();
while self.cursor.eat_punct(Punct::Star) {
let quals = self.pointer_quals();
let attrs = self.attributes();
out.push(Derived::Pointer { quals, attrs });
}
out
}
fn pointer_quals(&mut self) -> Quals {
let mut quals = Quals::NONE;
loop {
let Some(word) = self.cursor.current().keyword() else { return quals };
let one = match word {
Keyword::Const => Quals::CONST,
Keyword::Volatile => Quals::VOLATILE,
Keyword::Restrict => Quals::RESTRICT,
Keyword::Atomic => Quals::ATOMIC,
_ => return quals,
};
self.cursor.bump();
quals = quals.with(one);
}
}
fn declarator_suffixes(&mut self, out: &mut Vec<Derived>) {
loop {
if self.cursor.at_punct(Punct::LBracket) {
if !self.enter() {
self.cursor.bump();
return;
}
self.cursor.bump();
out.push(self.array_suffix());
self.expect_punct(Punct::RBracket);
self.leave();
} else if self.cursor.at_punct(Punct::LParen) {
if !self.enter() {
self.cursor.bump();
return;
}
self.cursor.bump();
out.push(self.parameter_list());
self.expect_punct(Punct::RParen);
self.leave();
} else {
return;
}
}
}
fn array_suffix(&mut self) -> Derived {
let mut quals = Quals::NONE;
let mut has_static = false;
loop {
if self.cursor.eat_keyword(Keyword::Static) {
has_static = true;
continue;
}
let before = quals;
quals = quals.with(self.pointer_quals());
if quals == before {
break;
}
}
let size = if self.cursor.at_punct(Punct::RBracket) {
ArraySize::Unspecified
} else if self.cursor.at_punct(Punct::Star)
&& self.cursor.peek(1).punct() == Some(Punct::RBracket)
{
self.cursor.bump();
ArraySize::Star
} else {
ArraySize::Expr(self.assign_expr())
};
Derived::Array { size, quals, has_static }
}
fn parameter_list(&mut self) -> Derived {
if self.cursor.at_punct(Punct::RParen) {
return Derived::Function {
params: ParamList::EMPTY,
variadic: false,
kind: ParamKind::Empty,
};
}
if self.cursor.at_keyword(Keyword::Void)
&& self.cursor.peek(1).punct() == Some(Punct::RParen)
{
self.cursor.bump();
return Derived::Function {
params: ParamList::EMPTY,
variadic: false,
kind: ParamKind::Void,
};
}
if self.cursor.current().ident().is_some() && !self.starts_decl_specs(self.cursor.current())
{
return self.identifier_list();
}
self.scopes.push();
let mut params = Vec::new();
let mut variadic = false;
loop {
if self.cursor.at_punct(Punct::RParen) || self.cursor.is_eof() {
break;
}
if self.cursor.eat_punct(Punct::Ellipsis) {
variadic = true;
break;
}
let before = self.cursor.index();
params.push(self.parameter());
if !self.cursor.eat_punct(Punct::Comma) {
break;
}
if self.cursor.index() == before {
break;
}
}
self.scopes.pop();
let params = self.ast.add_param_list(¶ms);
Derived::Function { params, variadic, kind: ParamKind::Prototype }
}
fn parameter(&mut self) -> Param {
let start = self.cursor.span();
let specs = self.decl_specs();
let declarator = self.any_declarator(DeclKind::Either);
if let Some(name) = self.ast[declarator].name {
self.scopes.declare(name, IdentKind::Ordinary);
}
let attrs = self.attributes();
Param { specs: Some(specs), declarator, attrs, span: self.span_from(start) }
}
fn identifier_list(&mut self) -> Derived {
let mut params = Vec::new();
loop {
let start = self.cursor.span();
let before = self.cursor.index();
let Some((name, name_span)) = self.expect_ident() else { break };
let declarator = self.ast.add_declarator(Declarator {
name: Some(name),
name_span,
derived: DerivedList::EMPTY,
span: name_span,
});
params.push(Param {
specs: None,
declarator,
attrs: AttrList::EMPTY,
span: self.span_from(start),
});
if !self.cursor.eat_punct(Punct::Comma) {
break;
}
if self.cursor.index() == before {
break;
}
}
let params = self.ast.add_param_list(¶ms);
Derived::Function { params, variadic: false, kind: ParamKind::Identifiers }
}
pub(crate) fn declare_params(&mut self, declarator: DeclaratorId) {
let derived = self.ast[declarator].derived;
let Some(&first) = self.ast[derived].first() else { return };
let Derived::Function { params, .. } = first else { return };
for index in 0..params.len() {
let param = self.ast[params][index];
if let Some(name) = self.ast[param.declarator].name {
self.scopes.declare(name, IdentKind::Ordinary);
}
}
}
}