use std::collections::{HashMap, HashSet};
use crate::ast::*;
use crate::error::{CompileError, ParseError, Result};
use crate::intern::{InternedStr, StringInterner};
use crate::macro_infer::detect_assert_kind;
use crate::preprocessor::Preprocessor;
use crate::lexer::{Lexer, LookupOnly};
use crate::source::{FileId, SourceLocation};
use crate::token::{MacroBeginInfo, MacroInvocationKind, Token, TokenId, TokenKind};
use crate::token_source::{TokenSliceRef, TokenSource};
#[derive(Debug, Default)]
pub struct MacroContext {
stack: Vec<MacroBeginInfo>,
}
impl MacroContext {
pub fn new() -> Self {
Self { stack: Vec::new() }
}
pub fn push(&mut self, info: MacroBeginInfo) {
self.stack.push(info);
}
pub fn pop(&mut self) -> Option<MacroBeginInfo> {
self.stack.pop()
}
pub fn is_in_macro(&self) -> bool {
!self.stack.is_empty()
}
pub fn build_macro_info(&self, interner: &StringInterner) -> Option<MacroExpansionInfo> {
if self.stack.is_empty() {
return None;
}
let mut info = MacroExpansionInfo::new();
for begin_info in &self.stack {
let args = match &begin_info.kind {
crate::token::MacroInvocationKind::Object => None,
crate::token::MacroInvocationKind::Function { args } => {
Some(args.iter().map(|arg_tokens| {
arg_tokens.iter()
.map(|t| t.kind.format(interner))
.collect::<Vec<_>>()
.join(" ")
}).collect())
}
};
info.push(MacroInvocation {
name: begin_info.macro_name,
call_loc: begin_info.call_loc.clone(),
args,
});
}
Some(info)
}
pub fn depth(&self) -> usize {
self.stack.len()
}
}
pub struct Parser<'a, S: TokenSource> {
source: &'a mut S,
current: Token,
typedefs: HashSet<InternedStr>,
macro_ctx: MacroContext,
handle_macro_markers: bool,
allow_missing_semi: bool,
pub function_call_count: usize,
pub deref_count: usize,
generic_params: HashMap<InternedStr, usize>,
detected_type_params: HashSet<InternedStr>,
}
impl<'a> Parser<'a, Preprocessor> {
pub fn new(pp: &'a mut Preprocessor) -> Result<Self> {
Self::from_source(pp)
}
pub fn parse_each<F>(&mut self, mut callback: F) -> Result<()>
where
F: FnMut(&ExternalDecl, &crate::source::SourceLocation, &std::path::Path, &StringInterner) -> std::ops::ControlFlow<()>,
{
while !self.is_eof() {
let loc = self.current.loc.clone();
let decl = self.parse_external_decl()?;
let path = self.source.files().get_path(loc.file_id);
let interner = self.source.interner();
if callback(&decl, &loc, path, interner).is_break() {
break;
}
}
Ok(())
}
pub fn parse_each_with_pp<F>(&mut self, mut callback: F) -> Result<()>
where
F: FnMut(&ExternalDecl, &crate::source::SourceLocation, &std::path::Path, &mut Preprocessor) -> std::ops::ControlFlow<()>,
{
while !self.is_eof() {
let loc = self.current.loc.clone();
let decl = self.parse_external_decl()?;
let path = self.source.files().get_path(loc.file_id).to_path_buf();
if callback(&decl, &loc, &path, self.source).is_break() {
break;
}
}
Ok(())
}
}
impl<'a, S: TokenSource> Parser<'a, S> {
pub fn from_source(source: &'a mut S) -> Result<Self> {
let mut typedefs = HashSet::new();
typedefs.insert(source.interner_mut().intern("__builtin_va_list"));
let mut parser = Self {
source,
current: Token::default(),
typedefs,
macro_ctx: MacroContext::new(),
handle_macro_markers: false,
allow_missing_semi: false,
function_call_count: 0,
deref_count: 0,
generic_params: HashMap::new(),
detected_type_params: HashSet::new(),
};
parser.current = parser.inner_next_token()?;
Ok(parser)
}
pub fn from_source_with_typedefs(source: &'a mut S, typedefs: HashSet<InternedStr>) -> Result<Self> {
let mut parser = Self {
source,
current: Token::default(),
typedefs,
macro_ctx: MacroContext::new(),
handle_macro_markers: false,
allow_missing_semi: false,
function_call_count: 0,
deref_count: 0,
generic_params: HashMap::new(),
detected_type_params: HashSet::new(),
};
parser.current = parser.inner_next_token()?;
Ok(parser)
}
pub fn set_handle_macro_markers(&mut self, enabled: bool) -> Result<()> {
self.handle_macro_markers = enabled;
if enabled {
while matches!(
self.current.kind,
TokenKind::MacroBegin(_) | TokenKind::MacroEnd(_)
) {
match &self.current.kind {
TokenKind::MacroBegin(info) => {
self.macro_ctx.push((**info).clone());
}
TokenKind::MacroEnd(_) => {
self.macro_ctx.pop();
}
_ => {}
}
self.current = self.source.next_token()?;
}
}
Ok(())
}
pub fn interner(&self) -> &crate::intern::StringInterner {
self.source.interner()
}
pub fn typedefs(&self) -> &HashSet<InternedStr> {
&self.typedefs
}
pub fn parse(&mut self) -> Result<TranslationUnit> {
let mut decls = Vec::new();
while !self.is_eof() {
let decl = self.parse_external_decl()?;
decls.push(decl);
}
Ok(TranslationUnit { decls })
}
pub fn parse_expr_only(&mut self) -> Result<Expr> {
self.parse_expr()
}
pub fn parse_stmt_allow_missing_semi(&mut self) -> Result<Stmt> {
self.allow_missing_semi = true;
let result = self.parse_stmt();
self.allow_missing_semi = false;
result
}
fn parse_external_decl(&mut self) -> Result<ExternalDecl> {
let comments = self.current.leading_comments.clone();
let loc = self.current.loc.clone();
let is_target = self.source.is_file_in_target(loc.file_id);
let specs = self.parse_decl_specs()?;
if self.check(&TokenKind::Semi) {
self.advance()?;
return Ok(ExternalDecl::Declaration(Declaration {
specs,
declarators: Vec::new(),
info: NodeInfo::new(loc),
comments,
is_target,
}));
}
let declarator = self.parse_declarator()?;
self.try_skip_attribute()?;
if self.check(&TokenKind::LBrace) {
let call_count_before = self.function_call_count;
let deref_count_before = self.deref_count;
let body = self.parse_compound_stmt()?;
let function_call_count = self.function_call_count - call_count_before;
let deref_count = self.deref_count - deref_count_before;
return Ok(ExternalDecl::FunctionDef(FunctionDef {
specs,
declarator,
body,
info: NodeInfo::new(loc),
comments,
is_target,
function_call_count,
deref_count,
}));
}
let mut declarators = Vec::new();
let init = if self.check(&TokenKind::Eq) {
self.advance()?;
Some(self.parse_initializer()?)
} else {
None
};
declarators.push(InitDeclarator { declarator, init });
while self.check(&TokenKind::Comma) {
self.advance()?;
let declarator = self.parse_declarator()?;
let init = if self.check(&TokenKind::Eq) {
self.advance()?;
Some(self.parse_initializer()?)
} else {
None
};
declarators.push(InitDeclarator { declarator, init });
}
self.try_skip_attribute()?;
self.expect(&TokenKind::Semi)?;
if specs.storage == Some(StorageClass::Typedef) {
for d in &declarators {
if let Some(name) = d.declarator.name {
self.typedefs.insert(name);
}
}
}
Ok(ExternalDecl::Declaration(Declaration {
specs,
declarators,
info: NodeInfo::new(loc),
comments,
is_target,
}))
}
fn parse_decl_specs(&mut self) -> Result<DeclSpecs> {
let mut specs = DeclSpecs::default();
loop {
match &self.current.kind {
TokenKind::KwExtension => {
self.advance()?;
continue;
}
TokenKind::KwThreadLocal | TokenKind::KwThread => {
self.advance()?;
continue;
}
TokenKind::KwTypedef => {
specs.storage = Some(StorageClass::Typedef);
self.advance()?;
}
TokenKind::KwExtern => {
specs.storage = Some(StorageClass::Extern);
self.advance()?;
}
TokenKind::KwStatic => {
specs.storage = Some(StorageClass::Static);
self.advance()?;
}
TokenKind::KwAuto => {
specs.storage = Some(StorageClass::Auto);
self.advance()?;
}
TokenKind::KwRegister => {
specs.storage = Some(StorageClass::Register);
self.advance()?;
}
TokenKind::KwInline | TokenKind::KwInline2 | TokenKind::KwInline3 => {
specs.is_inline = true;
self.advance()?;
}
TokenKind::KwConst | TokenKind::KwConst2 | TokenKind::KwConst3 => {
specs.qualifiers.is_const = true;
self.advance()?;
}
TokenKind::KwVolatile | TokenKind::KwVolatile2 | TokenKind::KwVolatile3 => {
specs.qualifiers.is_volatile = true;
self.advance()?;
}
TokenKind::KwRestrict | TokenKind::KwRestrict2 | TokenKind::KwRestrict3 => {
specs.qualifiers.is_restrict = true;
self.advance()?;
}
TokenKind::KwAtomic => {
specs.qualifiers.is_atomic = true;
self.advance()?;
}
TokenKind::KwVoid => {
specs.type_specs.push(TypeSpec::Void);
self.advance()?;
}
TokenKind::KwChar => {
specs.type_specs.push(TypeSpec::Char);
self.advance()?;
}
TokenKind::KwShort => {
specs.type_specs.push(TypeSpec::Short);
self.advance()?;
}
TokenKind::KwInt => {
specs.type_specs.push(TypeSpec::Int);
self.advance()?;
}
TokenKind::KwLong => {
specs.type_specs.push(TypeSpec::Long);
self.advance()?;
}
TokenKind::KwFloat => {
specs.type_specs.push(TypeSpec::Float);
self.advance()?;
}
TokenKind::KwDouble => {
specs.type_specs.push(TypeSpec::Double);
self.advance()?;
}
TokenKind::KwSigned | TokenKind::KwSigned2 => {
specs.type_specs.push(TypeSpec::Signed);
self.advance()?;
}
TokenKind::KwUnsigned => {
specs.type_specs.push(TypeSpec::Unsigned);
self.advance()?;
}
TokenKind::KwBool | TokenKind::KwBool2 => {
specs.type_specs.push(TypeSpec::Bool);
self.advance()?;
}
TokenKind::KwComplex => {
specs.type_specs.push(TypeSpec::Complex);
self.advance()?;
}
TokenKind::KwFloat16 => {
specs.type_specs.push(TypeSpec::Float16);
self.advance()?;
}
TokenKind::KwFloat32 => {
specs.type_specs.push(TypeSpec::Float32);
self.advance()?;
}
TokenKind::KwFloat64 => {
specs.type_specs.push(TypeSpec::Float64);
self.advance()?;
}
TokenKind::KwFloat128 => {
specs.type_specs.push(TypeSpec::Float128);
self.advance()?;
}
TokenKind::KwFloat32x => {
specs.type_specs.push(TypeSpec::Float32x);
self.advance()?;
}
TokenKind::KwFloat64x => {
specs.type_specs.push(TypeSpec::Float64x);
self.advance()?;
}
TokenKind::KwInt128 => {
specs.type_specs.push(TypeSpec::Int128);
self.advance()?;
}
TokenKind::KwTypeof | TokenKind::KwTypeof2 | TokenKind::KwTypeof3 => {
self.advance()?;
self.expect(&TokenKind::LParen)?;
let expr = self.parse_expr()?;
self.expect(&TokenKind::RParen)?;
specs.type_specs.push(TypeSpec::TypeofExpr(Box::new(expr)));
}
TokenKind::KwStruct => {
specs.type_specs.push(self.parse_struct_or_union(true)?);
}
TokenKind::KwUnion => {
specs.type_specs.push(self.parse_struct_or_union(false)?);
}
TokenKind::KwEnum => {
specs.type_specs.push(self.parse_enum()?);
}
TokenKind::KwAttribute | TokenKind::KwAttribute2 => {
self.skip_attribute()?;
}
TokenKind::Ident(id) if self.typedefs.contains(id) || self.detected_type_params.contains(id) => {
let id = *id;
specs.type_specs.push(TypeSpec::TypedefName(id));
self.advance()?;
}
_ => break,
}
}
Ok(specs)
}
fn parse_struct_or_union(&mut self, is_struct: bool) -> Result<TypeSpec> {
let loc = self.current.loc.clone();
self.advance()?;
self.try_skip_attribute()?;
let name = self.current_ident();
if name.is_some() {
self.advance()?;
}
let members = if self.check(&TokenKind::LBrace) {
self.advance()?;
let mut members = Vec::new();
while !self.check(&TokenKind::RBrace) {
members.push(self.parse_struct_member()?);
}
self.expect(&TokenKind::RBrace)?;
Some(members)
} else {
None
};
let spec = StructSpec { name, members, loc };
if is_struct {
Ok(TypeSpec::Struct(spec))
} else {
Ok(TypeSpec::Union(spec))
}
}
fn parse_struct_member(&mut self) -> Result<StructMember> {
let specs = self.parse_decl_specs()?;
let mut declarators = Vec::new();
loop {
let declarator = if self.check(&TokenKind::Colon) {
None
} else if self.check(&TokenKind::Semi) {
None
} else {
Some(self.parse_declarator()?)
};
self.try_skip_attribute()?;
let bitfield = if self.check(&TokenKind::Colon) {
self.advance()?;
Some(Box::new(self.parse_conditional_expr()?))
} else {
None
};
declarators.push(StructDeclarator { declarator, bitfield });
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::Semi)?;
Ok(StructMember { specs, declarators })
}
fn parse_enum(&mut self) -> Result<TypeSpec> {
let loc = self.current.loc.clone();
self.advance()?;
let name = self.current_ident();
if name.is_some() {
self.advance()?;
}
let enumerators = if self.check(&TokenKind::LBrace) {
self.advance()?;
let mut enums = Vec::new();
while !self.check(&TokenKind::RBrace) {
let eloc = self.current.loc.clone();
let ename = self.expect_ident()?;
let value = if self.check(&TokenKind::Eq) {
self.advance()?;
Some(Box::new(self.parse_conditional_expr()?))
} else {
None
};
enums.push(Enumerator {
name: ename,
value,
loc: eloc,
});
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RBrace)?;
Some(enums)
} else {
None
};
Ok(TypeSpec::Enum(EnumSpec {
name,
enumerators,
loc,
}))
}
fn parse_declarator(&mut self) -> Result<Declarator> {
let loc = self.current.loc.clone();
let mut derived = Vec::new();
while self.check(&TokenKind::Star) {
self.advance()?;
let qualifiers = self.parse_type_qualifiers()?;
derived.push(DerivedDecl::Pointer(qualifiers));
}
let (name, inner_derived) = self.parse_direct_declarator()?;
derived.extend(inner_derived);
Ok(Declarator {
name,
derived,
loc,
})
}
fn parse_direct_declarator(&mut self) -> Result<(Option<InternedStr>, Vec<DerivedDecl>)> {
let mut derived = Vec::new();
let name = if self.check(&TokenKind::LParen) {
self.advance()?;
let inner = self.parse_declarator()?;
self.expect(&TokenKind::RParen)?;
derived = inner.derived;
inner.name
} else if let Some(id) = self.current_ident() {
self.advance()?;
Some(id)
} else {
None
};
loop {
if self.check(&TokenKind::LBracket) {
derived.push(self.parse_array_declarator()?);
} else if self.check(&TokenKind::LParen) {
derived.push(self.parse_function_declarator()?);
} else {
break;
}
}
Ok((name, derived))
}
fn parse_array_declarator(&mut self) -> Result<DerivedDecl> {
self.advance()?;
let mut qualifiers = TypeQualifiers::default();
let mut is_static = false;
let mut is_vla = false;
loop {
match &self.current.kind {
TokenKind::KwStatic => {
is_static = true;
self.advance()?;
}
TokenKind::KwConst | TokenKind::KwConst2 | TokenKind::KwConst3 => {
qualifiers.is_const = true;
self.advance()?;
}
TokenKind::KwVolatile | TokenKind::KwVolatile2 | TokenKind::KwVolatile3 => {
qualifiers.is_volatile = true;
self.advance()?;
}
TokenKind::KwRestrict | TokenKind::KwRestrict2 | TokenKind::KwRestrict3 => {
qualifiers.is_restrict = true;
self.advance()?;
}
_ => break,
}
}
let size = if self.check(&TokenKind::RBracket) {
None
} else if self.check(&TokenKind::Star) {
is_vla = true;
self.advance()?;
None
} else {
Some(Box::new(self.parse_assignment_expr()?))
};
self.expect(&TokenKind::RBracket)?;
Ok(DerivedDecl::Array(ArrayDecl {
size,
qualifiers,
is_static,
is_vla,
}))
}
fn parse_function_declarator(&mut self) -> Result<DerivedDecl> {
self.advance()?;
if self.check(&TokenKind::RParen) {
self.advance()?;
return Ok(DerivedDecl::Function(ParamList {
params: Vec::new(),
is_variadic: false,
}));
}
let mut params = Vec::new();
let mut is_variadic = false;
loop {
if self.check(&TokenKind::Ellipsis) {
is_variadic = true;
self.advance()?;
break;
}
let loc = self.current.loc.clone();
let specs = self.parse_decl_specs()?;
let declarator = if self.check(&TokenKind::Comma) || self.check(&TokenKind::RParen) {
None
} else {
Some(self.parse_declarator()?)
};
self.try_skip_attribute()?;
params.push(ParamDecl {
specs,
declarator,
loc,
});
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RParen)?;
Ok(DerivedDecl::Function(ParamList { params, is_variadic }))
}
fn parse_type_qualifiers(&mut self) -> Result<TypeQualifiers> {
let mut qualifiers = TypeQualifiers::default();
loop {
match &self.current.kind {
TokenKind::KwConst | TokenKind::KwConst2 | TokenKind::KwConst3 => {
qualifiers.is_const = true;
self.advance()?;
}
TokenKind::KwVolatile | TokenKind::KwVolatile2 | TokenKind::KwVolatile3 => {
qualifiers.is_volatile = true;
self.advance()?;
}
TokenKind::KwRestrict | TokenKind::KwRestrict2 | TokenKind::KwRestrict3 => {
qualifiers.is_restrict = true;
self.advance()?;
}
TokenKind::KwAtomic => {
qualifiers.is_atomic = true;
self.advance()?;
}
_ => break,
}
}
Ok(qualifiers)
}
fn parse_initializer(&mut self) -> Result<Initializer> {
if self.check(&TokenKind::LBrace) {
self.advance()?;
let mut items = Vec::new();
while !self.check(&TokenKind::RBrace) {
let designation = self.parse_designation()?;
let init = self.parse_initializer()?;
items.push(InitializerItem { designation, init });
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RBrace)?;
Ok(Initializer::List(items))
} else {
Ok(Initializer::Expr(Box::new(self.parse_assignment_expr()?)))
}
}
fn parse_designation(&mut self) -> Result<Vec<Designator>> {
let mut designators = Vec::new();
loop {
if self.check(&TokenKind::LBracket) {
self.advance()?;
let index = self.parse_conditional_expr()?;
self.expect(&TokenKind::RBracket)?;
designators.push(Designator::Index(Box::new(index)));
} else if self.check(&TokenKind::Dot) {
self.advance()?;
let name = self.expect_ident()?;
designators.push(Designator::Member(name));
} else {
break;
}
}
if !designators.is_empty() {
self.expect(&TokenKind::Eq)?;
}
Ok(designators)
}
pub fn parse_type_name(&mut self) -> Result<TypeName> {
let specs = self.parse_decl_specs()?;
let declarator = if self.check(&TokenKind::RParen) {
None
} else {
Some(self.parse_abstract_declarator()?)
};
Ok(TypeName { specs, declarator })
}
fn parse_abstract_declarator(&mut self) -> Result<AbstractDeclarator> {
let mut derived = Vec::new();
while self.check(&TokenKind::Star) {
self.advance()?;
let qualifiers = self.parse_type_qualifiers()?;
derived.push(DerivedDecl::Pointer(qualifiers));
}
if self.check(&TokenKind::LParen) {
self.advance()?;
if !self.check(&TokenKind::RParen) && !self.is_type_start() {
let inner = self.parse_abstract_declarator()?;
self.expect(&TokenKind::RParen)?;
derived.extend(inner.derived);
} else {
let params = self.parse_param_list_inner()?;
derived.push(DerivedDecl::Function(params));
}
}
loop {
if self.check(&TokenKind::LBracket) {
derived.push(self.parse_array_declarator()?);
} else if self.check(&TokenKind::LParen) {
derived.push(self.parse_function_declarator()?);
} else {
break;
}
}
Ok(AbstractDeclarator { derived })
}
fn parse_param_list_inner(&mut self) -> Result<ParamList> {
if self.check(&TokenKind::RParen) {
self.advance()?;
return Ok(ParamList {
params: Vec::new(),
is_variadic: false,
});
}
let mut params = Vec::new();
let mut is_variadic = false;
loop {
if self.check(&TokenKind::Ellipsis) {
is_variadic = true;
self.advance()?;
break;
}
let loc = self.current.loc.clone();
let specs = self.parse_decl_specs()?;
let declarator = if self.check(&TokenKind::Comma) || self.check(&TokenKind::RParen) {
None
} else if self.check(&TokenKind::Star) || self.check(&TokenKind::LParen) || self.check(&TokenKind::LBracket) {
Some(self.parse_declarator()?)
} else if let Some(id) = self.current_ident() {
if !self.typedefs.contains(&id) {
Some(self.parse_declarator()?)
} else {
None
}
} else {
None
};
self.try_skip_attribute()?;
params.push(ParamDecl {
specs,
declarator,
loc,
});
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RParen)?;
Ok(ParamList { params, is_variadic })
}
fn parse_compound_stmt(&mut self) -> Result<CompoundStmt> {
let loc = self.current.loc.clone();
self.expect(&TokenKind::LBrace)?;
let mut items = Vec::new();
while !self.check(&TokenKind::RBrace) {
items.push(self.parse_block_item()?);
}
self.expect(&TokenKind::RBrace)?;
Ok(CompoundStmt { items, info: NodeInfo::new(loc) })
}
pub(crate) fn parse_block_item(&mut self) -> Result<BlockItem> {
if self.is_declaration_start() {
Ok(BlockItem::Decl(self.parse_declaration()?))
} else {
Ok(BlockItem::Stmt(self.parse_stmt()?))
}
}
fn parse_declaration(&mut self) -> Result<Declaration> {
let comments = self.current.leading_comments.clone();
let loc = self.current.loc.clone();
let is_target = self.source.is_file_in_target(loc.file_id);
let specs = self.parse_decl_specs()?;
if self.check(&TokenKind::Semi) {
self.advance()?;
return Ok(Declaration {
specs,
declarators: Vec::new(),
info: NodeInfo::new(loc),
comments,
is_target,
});
}
let mut declarators = Vec::new();
loop {
let declarator = self.parse_declarator()?;
self.try_skip_attribute()?;
let init = if self.check(&TokenKind::Eq) {
self.advance()?;
Some(self.parse_initializer()?)
} else {
None
};
declarators.push(InitDeclarator { declarator, init });
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.try_skip_attribute()?;
self.expect(&TokenKind::Semi)?;
if specs.storage == Some(StorageClass::Typedef) {
for d in &declarators {
if let Some(name) = d.declarator.name {
self.typedefs.insert(name);
}
}
}
Ok(Declaration {
specs,
declarators,
info: NodeInfo::new(loc),
comments,
is_target,
})
}
fn parse_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
match &self.current.kind {
TokenKind::KwCase => return self.parse_case_stmt(),
TokenKind::KwDefault => return self.parse_default_stmt(),
TokenKind::LBrace => return Ok(Stmt::Compound(self.parse_compound_stmt()?)),
TokenKind::KwIf => return self.parse_if_stmt(),
TokenKind::KwSwitch => return self.parse_switch_stmt(),
TokenKind::KwWhile => return self.parse_while_stmt(),
TokenKind::KwDo => return self.parse_do_while_stmt(),
TokenKind::KwFor => return self.parse_for_stmt(),
TokenKind::KwGoto => {
self.advance()?;
let name = self.expect_ident()?;
self.expect(&TokenKind::Semi)?;
return Ok(Stmt::Goto(name, loc));
}
TokenKind::KwContinue => {
self.advance()?;
self.expect(&TokenKind::Semi)?;
return Ok(Stmt::Continue(loc));
}
TokenKind::KwBreak => {
self.advance()?;
self.expect(&TokenKind::Semi)?;
return Ok(Stmt::Break(loc));
}
TokenKind::KwReturn => {
self.advance()?;
let expr = if self.check(&TokenKind::Semi) {
None
} else {
Some(Box::new(self.parse_expr()?))
};
self.expect(&TokenKind::Semi)?;
return Ok(Stmt::Return(expr, loc));
}
TokenKind::KwAsm | TokenKind::KwAsm2 | TokenKind::KwAsm3 => {
return self.parse_asm_stmt();
}
_ => {}
}
if self.check(&TokenKind::Semi) {
self.advance()?;
return Ok(Stmt::Expr(None, loc));
}
let expr = self.parse_expr()?;
if self.check(&TokenKind::Colon) {
if let ExprKind::Ident(name) = expr.kind {
self.advance()?;
let stmt = self.parse_stmt()?;
return Ok(Stmt::Label {
name,
stmt: Box::new(stmt),
loc,
});
}
}
self.expect(&TokenKind::Semi)?;
Ok(Stmt::Expr(Some(Box::new(expr)), loc))
}
fn parse_if_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; self.expect(&TokenKind::LParen)?;
let cond = Box::new(self.parse_expr()?);
self.expect(&TokenKind::RParen)?;
let then_stmt = Box::new(self.parse_stmt()?);
let else_stmt = if matches!(self.current.kind, TokenKind::KwElse) {
self.advance()?;
Some(Box::new(self.parse_stmt()?))
} else {
None
};
Ok(Stmt::If {
cond,
then_stmt,
else_stmt,
loc,
})
}
fn parse_switch_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; self.expect(&TokenKind::LParen)?;
let expr = Box::new(self.parse_expr()?);
self.expect(&TokenKind::RParen)?;
let body = Box::new(self.parse_stmt()?);
Ok(Stmt::Switch { expr, body, loc })
}
fn parse_while_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; self.expect(&TokenKind::LParen)?;
let cond = Box::new(self.parse_expr()?);
self.expect(&TokenKind::RParen)?;
let body = Box::new(self.parse_stmt()?);
Ok(Stmt::While { cond, body, loc })
}
fn parse_do_while_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; let body = Box::new(self.parse_stmt()?);
if !matches!(self.current.kind, TokenKind::KwWhile) {
return Err(CompileError::Parse {
loc: self.current.loc.clone(),
kind: ParseError::UnexpectedToken {
expected: "while".to_string(),
found: self.current.kind.clone(),
},
});
}
self.advance()?;
self.expect(&TokenKind::LParen)?;
let cond = Box::new(self.parse_expr()?);
self.expect(&TokenKind::RParen)?;
if self.allow_missing_semi {
if self.check(&TokenKind::Semi) {
self.advance()?;
}
} else {
self.expect(&TokenKind::Semi)?;
}
Ok(Stmt::DoWhile { body, cond, loc })
}
fn parse_for_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; self.expect(&TokenKind::LParen)?;
let init = if self.check(&TokenKind::Semi) {
self.advance()?;
None
} else if self.is_declaration_start() {
let decl = self.parse_declaration()?;
Some(ForInit::Decl(decl))
} else {
let expr = self.parse_expr()?;
self.expect(&TokenKind::Semi)?;
Some(ForInit::Expr(Box::new(expr)))
};
let cond = if self.check(&TokenKind::Semi) {
None
} else {
Some(Box::new(self.parse_expr()?))
};
self.expect(&TokenKind::Semi)?;
let step = if self.check(&TokenKind::RParen) {
None
} else {
Some(Box::new(self.parse_expr()?))
};
self.expect(&TokenKind::RParen)?;
let body = Box::new(self.parse_stmt()?);
Ok(Stmt::For {
init,
cond,
step,
body,
loc,
})
}
fn parse_case_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; let expr = Box::new(self.parse_conditional_expr()?);
self.expect(&TokenKind::Colon)?;
let stmt = Box::new(self.parse_stmt()?);
Ok(Stmt::Case { expr, stmt, loc })
}
fn parse_default_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?; self.expect(&TokenKind::Colon)?;
let stmt = Box::new(self.parse_stmt()?);
Ok(Stmt::Default { stmt, loc })
}
fn parse_asm_stmt(&mut self) -> Result<Stmt> {
let loc = self.current.loc.clone();
self.advance()?;
while matches!(
self.current.kind,
TokenKind::KwVolatile | TokenKind::KwVolatile2 | TokenKind::KwVolatile3
) {
self.advance()?;
}
self.expect(&TokenKind::LParen)?;
self.skip_balanced_parens()?;
self.expect(&TokenKind::Semi)?;
Ok(Stmt::Asm { loc })
}
fn parse_expr(&mut self) -> Result<Expr> {
let lhs = self.parse_assignment_expr()?;
if self.check(&TokenKind::Comma) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_expr()?;
return Ok(Expr::new(
ExprKind::Comma {
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
));
}
Ok(lhs)
}
fn parse_assignment_expr(&mut self) -> Result<Expr> {
let lhs = self.parse_conditional_expr()?;
let op = match &self.current.kind {
TokenKind::Eq => Some(AssignOp::Assign),
TokenKind::StarEq => Some(AssignOp::MulAssign),
TokenKind::SlashEq => Some(AssignOp::DivAssign),
TokenKind::PercentEq => Some(AssignOp::ModAssign),
TokenKind::PlusEq => Some(AssignOp::AddAssign),
TokenKind::MinusEq => Some(AssignOp::SubAssign),
TokenKind::LtLtEq => Some(AssignOp::ShlAssign),
TokenKind::GtGtEq => Some(AssignOp::ShrAssign),
TokenKind::AmpEq => Some(AssignOp::AndAssign),
TokenKind::CaretEq => Some(AssignOp::XorAssign),
TokenKind::PipeEq => Some(AssignOp::OrAssign),
_ => None,
};
if let Some(op) = op {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_assignment_expr()?;
return Ok(Expr::new(
ExprKind::Assign {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
));
}
Ok(lhs)
}
fn parse_conditional_expr(&mut self) -> Result<Expr> {
let cond = self.parse_logical_or_expr()?;
if self.check(&TokenKind::Question) {
let loc = self.current.loc.clone();
self.advance()?;
let then_expr = self.parse_expr()?;
self.expect(&TokenKind::Colon)?;
let else_expr = self.parse_conditional_expr()?;
return Ok(Expr::new(
ExprKind::Conditional {
cond: Box::new(cond),
then_expr: Box::new(then_expr),
else_expr: Box::new(else_expr),
},
loc,
));
}
Ok(cond)
}
fn parse_logical_or_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_logical_and_expr()?;
while self.check(&TokenKind::PipePipe) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_logical_and_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op: BinOp::LogOr,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_logical_and_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_bitwise_or_expr()?;
while self.check(&TokenKind::AmpAmp) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_bitwise_or_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op: BinOp::LogAnd,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_bitwise_or_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_bitwise_xor_expr()?;
while self.check(&TokenKind::Pipe) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_bitwise_xor_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op: BinOp::BitOr,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_bitwise_xor_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_bitwise_and_expr()?;
while self.check(&TokenKind::Caret) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_bitwise_and_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op: BinOp::BitXor,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_bitwise_and_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_equality_expr()?;
while self.check(&TokenKind::Amp) {
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_equality_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op: BinOp::BitAnd,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_equality_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_relational_expr()?;
loop {
let op = match &self.current.kind {
TokenKind::EqEq => BinOp::Eq,
TokenKind::BangEq => BinOp::Ne,
_ => break,
};
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_relational_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_relational_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_shift_expr()?;
loop {
let op = match &self.current.kind {
TokenKind::Lt => BinOp::Lt,
TokenKind::Gt => BinOp::Gt,
TokenKind::LtEq => BinOp::Le,
TokenKind::GtEq => BinOp::Ge,
_ => break,
};
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_shift_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_shift_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_additive_expr()?;
loop {
let op = match &self.current.kind {
TokenKind::LtLt => BinOp::Shl,
TokenKind::GtGt => BinOp::Shr,
_ => break,
};
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_additive_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_additive_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_multiplicative_expr()?;
loop {
let op = match &self.current.kind {
TokenKind::Plus => BinOp::Add,
TokenKind::Minus => BinOp::Sub,
_ => break,
};
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_multiplicative_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_multiplicative_expr(&mut self) -> Result<Expr> {
let mut lhs = self.parse_cast_expr()?;
loop {
let op = match &self.current.kind {
TokenKind::Star => BinOp::Mul,
TokenKind::Slash => BinOp::Div,
TokenKind::Percent => BinOp::Mod,
_ => break,
};
let loc = self.current.loc.clone();
self.advance()?;
let rhs = self.parse_cast_expr()?;
lhs = Expr::new(
ExprKind::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
},
loc,
);
}
Ok(lhs)
}
fn parse_cast_expr(&mut self) -> Result<Expr> {
if self.check(&TokenKind::LParen) {
let loc = self.current.loc.clone();
self.advance()?;
if self.is_type_start() {
return self.finish_parse_cast_or_compound_lit(loc);
}
if let Some(id) = self.current_ident() {
if self.generic_params.contains_key(&id)
&& self.looks_like_generic_cast()
{
self.detected_type_params.insert(id);
return self.finish_parse_cast_or_compound_lit(loc);
}
}
if self.check(&TokenKind::LBrace) {
let stmt = self.parse_compound_stmt()?;
self.expect(&TokenKind::RParen)?;
let stmt_expr = Expr::new(ExprKind::StmtExpr(stmt), loc);
return self.parse_postfix_on(stmt_expr);
} else {
let expr = self.parse_expr()?;
self.expect(&TokenKind::RParen)?;
return self.parse_postfix_on(expr);
}
}
self.parse_unary_expr()
}
fn finish_parse_cast_or_compound_lit(&mut self, loc: SourceLocation) -> Result<Expr> {
let type_name = self.parse_type_name()?;
self.expect(&TokenKind::RParen)?;
if self.check(&TokenKind::LBrace) {
self.advance()?;
let mut items = Vec::new();
while !self.check(&TokenKind::RBrace) {
let designation = self.parse_designation()?;
let init = self.parse_initializer()?;
items.push(InitializerItem { designation, init });
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RBrace)?;
return Ok(Expr::new(
ExprKind::CompoundLit {
type_name: Box::new(type_name),
init: items,
},
loc,
));
}
let expr = self.parse_cast_expr()?;
Ok(Expr::new(
ExprKind::Cast {
type_name: Box::new(type_name),
expr: Box::new(expr),
},
loc,
))
}
fn looks_like_generic_cast(&mut self) -> bool {
let next1 = match self.source.next_token() {
Ok(t) => t,
Err(_) => return false,
};
let result = match &next1.kind {
TokenKind::Star => true,
TokenKind::RParen => {
let next2 = match self.source.next_token() {
Ok(t) => t,
Err(_) => {
self.source.unget_token(next1);
return false;
}
};
let is_cast = match &next2.kind {
TokenKind::LParen | TokenKind::Ident(_) | TokenKind::IntLit(_) | TokenKind::UIntLit(_)
| TokenKind::FloatLit(_)
| TokenKind::StringLit(_) | TokenKind::CharLit(_)
| TokenKind::Star | TokenKind::Amp | TokenKind::Bang | TokenKind::Tilde | TokenKind::KwSizeof => true,
TokenKind::Minus => {
let next3 = match self.source.next_token() {
Ok(t) => t,
Err(_) => {
self.source.unget_token(next2);
self.source.unget_token(next1);
return false;
}
};
let is_numeric = matches!(&next3.kind,
TokenKind::IntLit(_)
| TokenKind::UIntLit(_)
| TokenKind::FloatLit(_)
);
self.source.unget_token(next3);
is_numeric
}
_ => false,
};
self.source.unget_token(next2);
is_cast
}
_ => false,
};
self.source.unget_token(next1);
result
}
fn parse_postfix_on(&mut self, mut expr: Expr) -> Result<Expr> {
loop {
let loc = self.current.loc.clone();
match &self.current.kind {
TokenKind::LBracket => {
self.advance()?;
let index = self.parse_expr()?;
self.expect(&TokenKind::RBracket)?;
expr = Expr::new(
ExprKind::Index {
expr: Box::new(expr),
index: Box::new(index),
},
loc,
);
}
TokenKind::LParen => {
self.advance()?;
let mut args = Vec::new();
while !self.check(&TokenKind::RParen) {
args.push(self.parse_assignment_expr()?);
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
self.expect(&TokenKind::RParen)?;
self.function_call_count += 1;
expr = Expr::new(
ExprKind::Call {
func: Box::new(expr),
args,
},
loc,
);
}
TokenKind::Dot => {
self.advance()?;
let member = self.expect_ident()?;
expr = Expr::new(
ExprKind::Member {
expr: Box::new(expr),
member,
},
loc,
);
}
TokenKind::Arrow => {
self.advance()?;
let member = self.expect_ident()?;
self.deref_count += 1;
expr = Expr::new(
ExprKind::PtrMember {
expr: Box::new(expr),
member,
},
loc,
);
}
TokenKind::PlusPlus => {
self.advance()?;
expr = Expr::new(ExprKind::PostInc(Box::new(expr)), loc);
}
TokenKind::MinusMinus => {
self.advance()?;
expr = Expr::new(ExprKind::PostDec(Box::new(expr)), loc);
}
_ => break,
}
}
Ok(expr)
}
fn parse_unary_expr(&mut self) -> Result<Expr> {
let loc = self.current.loc.clone();
match &self.current.kind {
TokenKind::PlusPlus => {
self.advance()?;
let expr = self.parse_unary_expr()?;
Ok(Expr::new(ExprKind::PreInc(Box::new(expr)), loc))
}
TokenKind::MinusMinus => {
self.advance()?;
let expr = self.parse_unary_expr()?;
Ok(Expr::new(ExprKind::PreDec(Box::new(expr)), loc))
}
TokenKind::Amp => {
self.advance()?;
let expr = self.parse_cast_expr()?;
Ok(Expr::new(ExprKind::AddrOf(Box::new(expr)), loc))
}
TokenKind::Star => {
self.advance()?;
let expr = self.parse_cast_expr()?;
self.deref_count += 1;
Ok(Expr::new(ExprKind::Deref(Box::new(expr)), loc))
}
TokenKind::Plus => {
self.advance()?;
let expr = self.parse_cast_expr()?;
Ok(Expr::new(ExprKind::UnaryPlus(Box::new(expr)), loc))
}
TokenKind::Minus => {
self.advance()?;
let expr = self.parse_cast_expr()?;
Ok(Expr::new(ExprKind::UnaryMinus(Box::new(expr)), loc))
}
TokenKind::Tilde => {
self.advance()?;
let expr = self.parse_cast_expr()?;
Ok(Expr::new(ExprKind::BitNot(Box::new(expr)), loc))
}
TokenKind::Bang => {
self.advance()?;
let expr = self.parse_cast_expr()?;
Ok(Expr::new(ExprKind::LogNot(Box::new(expr)), loc))
}
TokenKind::KwSizeof => {
self.advance()?;
if self.check(&TokenKind::LParen) {
self.advance()?; if self.is_type_start() {
let type_name = self.parse_type_name()?;
self.expect(&TokenKind::RParen)?;
Ok(Expr::new(ExprKind::SizeofType(Box::new(type_name)), loc))
} else {
let expr = self.parse_expr()?;
self.expect(&TokenKind::RParen)?;
Ok(Expr::new(ExprKind::Sizeof(Box::new(expr)), loc))
}
} else {
let expr = self.parse_unary_expr()?;
Ok(Expr::new(ExprKind::Sizeof(Box::new(expr)), loc))
}
}
TokenKind::KwAlignof | TokenKind::KwAlignof2 | TokenKind::KwAlignof3 => {
self.advance()?;
self.expect(&TokenKind::LParen)?;
let type_name = self.parse_type_name()?;
self.expect(&TokenKind::RParen)?;
Ok(Expr::new(ExprKind::Alignof(Box::new(type_name)), loc))
}
TokenKind::KwExtension => {
self.advance()?;
self.parse_unary_expr()
}
_ => self.parse_postfix_expr(),
}
}
fn parse_postfix_expr(&mut self) -> Result<Expr> {
let mut expr = self.parse_primary_expr()?;
loop {
let loc = self.current.loc.clone();
match &self.current.kind {
TokenKind::LBracket => {
self.advance()?;
let index = self.parse_expr()?;
self.expect(&TokenKind::RBracket)?;
expr = Expr::new(
ExprKind::Index {
expr: Box::new(expr),
index: Box::new(index),
},
loc,
);
}
TokenKind::LParen => {
if let ExprKind::Ident(name) = &expr.kind {
if self.is_type_arg_builtin(*name) {
let builtin_name = *name;
self.advance()?; let args = self.parse_builtin_args()?;
self.expect(&TokenKind::RParen)?;
self.function_call_count += 1;
expr = Expr::new(
ExprKind::BuiltinCall { name: builtin_name, args },
loc,
);
continue;
}
}
self.advance()?;
let mut args = Vec::new();
if !self.check(&TokenKind::RParen) {
loop {
args.push(self.parse_assignment_expr()?);
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
}
self.expect(&TokenKind::RParen)?;
self.function_call_count += 1;
expr = Expr::new(
ExprKind::Call {
func: Box::new(expr),
args,
},
loc,
);
}
TokenKind::Dot => {
self.advance()?;
let member = self.expect_ident()?;
expr = Expr::new(
ExprKind::Member {
expr: Box::new(expr),
member,
},
loc,
);
}
TokenKind::Arrow => {
self.advance()?;
let member = self.expect_ident()?;
self.deref_count += 1;
expr = Expr::new(
ExprKind::PtrMember {
expr: Box::new(expr),
member,
},
loc,
);
}
TokenKind::PlusPlus => {
self.advance()?;
expr = Expr::new(ExprKind::PostInc(Box::new(expr)), loc);
}
TokenKind::MinusMinus => {
self.advance()?;
expr = Expr::new(ExprKind::PostDec(Box::new(expr)), loc);
}
_ => break,
}
}
Ok(expr)
}
fn parse_primary_expr(&mut self) -> Result<Expr> {
let loc = self.current.loc.clone();
match &self.current.kind {
TokenKind::Ident(id) => {
let id = *id;
self.advance()?;
Ok(Expr::new(ExprKind::Ident(id), loc))
}
TokenKind::IntLit(n) => {
let n = *n;
self.advance()?;
Ok(Expr::new(ExprKind::IntLit(n), loc))
}
TokenKind::UIntLit(n) => {
let n = *n;
self.advance()?;
Ok(Expr::new(ExprKind::UIntLit(n), loc))
}
TokenKind::FloatLit(f) => {
let f = *f;
self.advance()?;
Ok(Expr::new(ExprKind::FloatLit(f), loc))
}
TokenKind::CharLit(c) => {
let c = *c;
self.advance()?;
Ok(Expr::new(ExprKind::CharLit(c), loc))
}
TokenKind::StringLit(s) => {
let mut bytes = s.clone();
self.advance()?;
while let TokenKind::StringLit(s2) = &self.current.kind {
bytes.extend_from_slice(s2);
self.advance()?;
}
Ok(Expr::new(ExprKind::StringLit(bytes), loc))
}
TokenKind::LParen => {
self.advance()?;
if self.check(&TokenKind::LBrace) {
let stmt = self.parse_compound_stmt()?;
self.expect(&TokenKind::RParen)?;
Ok(Expr::new(ExprKind::StmtExpr(stmt), loc))
} else {
let expr = self.parse_expr()?;
self.expect(&TokenKind::RParen)?;
Ok(expr)
}
}
TokenKind::MacroBegin(info) if info.is_wrapped => {
self.parse_wrapped_macro_expr()
}
TokenKind::MacroBegin(info) if info.preserve_call => {
self.parse_macro_call_expr()
}
_ => Err(CompileError::Parse {
loc,
kind: ParseError::UnexpectedToken {
expected: "primary expression".to_string(),
found: self.current.kind.clone(),
},
}),
}
}
fn parse_wrapped_macro_expr(&mut self) -> Result<Expr> {
let loc = self.current.loc.clone();
let (marker_id, macro_name, args) = match &self.current.kind {
TokenKind::MacroBegin(info) if info.is_wrapped => {
let args = match &info.kind {
MacroInvocationKind::Function { args } => args.clone(),
MacroInvocationKind::Object => {
let name = self.source.interner().get(info.macro_name).to_string();
return Err(CompileError::Parse {
loc,
kind: ParseError::AssertNotFunctionMacro { macro_name: name },
});
}
};
(info.marker_id, info.macro_name, args)
}
_ => unreachable!("parse_wrapped_macro_expr called without wrapped MacroBegin"),
};
if args.len() != 1 {
let name = self.source.interner().get(macro_name).to_string();
return Err(CompileError::Parse {
loc,
kind: ParseError::InvalidAssertArgs {
macro_name: name,
arg_count: args.len(),
},
});
}
let condition = self.parse_expr_from_tokens(&args[0], &loc)?;
let macro_name_str = self.source.interner().get(macro_name);
let kind = detect_assert_kind(macro_name_str).unwrap_or(AssertKind::Assert);
self.skip_to_macro_end(marker_id)?;
let assert_expr = Expr::new(ExprKind::Assert {
kind,
condition: Box::new(condition),
}, loc.clone());
if self.is_expression_start() {
let next_expr = self.parse_assignment_expr()?;
Ok(Expr::new(
ExprKind::Comma {
lhs: Box::new(assert_expr),
rhs: Box::new(next_expr),
},
loc,
))
} else {
Ok(assert_expr)
}
}
fn parse_macro_call_expr(&mut self) -> Result<Expr> {
let loc = self.current.loc.clone();
let (marker_id, macro_name, raw_args, call_loc) = match &self.current.kind {
TokenKind::MacroBegin(info) if info.preserve_call => {
let args = match &info.kind {
MacroInvocationKind::Function { args } => args.clone(),
MacroInvocationKind::Object => Vec::new(),
};
(info.marker_id, info.macro_name, args, info.call_loc.clone())
}
_ => unreachable!("parse_macro_call_expr called without preserve_call MacroBegin"),
};
let expanded_tokens = self.collect_tokens_until_macro_end(marker_id)?;
let expanded = if expanded_tokens.is_empty() {
Expr::new(ExprKind::IntLit(0), loc.clone())
} else {
crate::parser::parse_expression_from_tokens_ref(
expanded_tokens,
self.source.interner(),
self.source.files(),
&self.typedefs,
)?
};
let parsed_args: Result<Vec<Expr>> = raw_args.iter()
.map(|arg_tokens| {
if arg_tokens.is_empty() {
Ok(Expr::new(ExprKind::IntLit(0), loc.clone()))
} else {
crate::parser::parse_expression_from_tokens_ref(
arg_tokens.clone(),
self.source.interner(),
self.source.files(),
&self.typedefs,
)
}
})
.collect();
let args = parsed_args?;
self.current = self.inner_next_token()?;
Ok(Expr::new(ExprKind::MacroCall {
name: macro_name,
args,
expanded: Box::new(expanded),
call_loc,
}, loc))
}
fn collect_tokens_until_macro_end(&mut self, target_marker_id: TokenId) -> Result<Vec<Token>> {
let mut tokens = Vec::new();
let mut nested_depth = 0;
loop {
let token = self.source.next_token()?;
match &token.kind {
TokenKind::MacroBegin(_) => {
nested_depth += 1;
tokens.push(token);
}
TokenKind::MacroEnd(info) => {
if nested_depth > 0 {
nested_depth -= 1;
tokens.push(token);
} else if info.begin_marker_id == target_marker_id {
return Ok(tokens);
} else {
tokens.push(token);
}
}
TokenKind::Eof => {
return Err(CompileError::Parse {
loc: token.loc,
kind: ParseError::UnexpectedToken {
expected: "MacroEnd".to_string(),
found: token.kind,
},
});
}
_ => {
tokens.push(token);
}
}
}
}
fn is_expression_start(&self) -> bool {
match &self.current.kind {
TokenKind::Ident(_)
| TokenKind::IntLit(_)
| TokenKind::UIntLit(_)
| TokenKind::FloatLit(_)
| TokenKind::CharLit(_)
| TokenKind::WideCharLit(_)
| TokenKind::StringLit(_)
| TokenKind::WideStringLit(_)
| TokenKind::LParen
| TokenKind::Star | TokenKind::Amp | TokenKind::Plus | TokenKind::Minus | TokenKind::Bang | TokenKind::Tilde | TokenKind::PlusPlus | TokenKind::MinusMinus | TokenKind::KwSizeof
| TokenKind::KwAlignof
| TokenKind::KwAlignof2
| TokenKind::KwAlignof3
| TokenKind::MacroBegin(_) => true, _ => false,
}
}
fn parse_expr_from_tokens(&self, tokens: &[Token], loc: &SourceLocation) -> Result<Expr> {
for token in tokens {
if let TokenKind::MacroBegin(info) = &token.kind {
if info.is_wrapped {
return Err(CompileError::Parse {
loc: loc.clone(),
kind: ParseError::NestedAssertNotSupported,
});
}
}
}
crate::parser::parse_expression_from_tokens_ref(
tokens.to_vec(),
self.source.interner(),
self.source.files(),
&self.typedefs,
)
}
fn skip_to_macro_end(&mut self, target_marker_id: TokenId) -> Result<()> {
loop {
let token = self.source.next_token()?;
match &token.kind {
TokenKind::MacroEnd(info) if info.begin_marker_id == target_marker_id => {
self.current = self.inner_next_token()?;
return Ok(());
}
TokenKind::Eof => {
return Err(CompileError::Parse {
loc: token.loc.clone(),
kind: ParseError::MacroEndNotFound,
});
}
_ => {
continue;
}
}
}
}
fn inner_next_token(&mut self) -> Result<Token> {
loop {
let token = self.source.next_token()?;
if !self.handle_macro_markers {
return Ok(token);
}
match &token.kind {
TokenKind::MacroBegin(info) => {
if info.is_wrapped {
return Ok(token);
}
if info.preserve_call {
return Ok(token);
}
self.macro_ctx.push((**info).clone());
continue; }
TokenKind::MacroEnd(_info) => {
self.macro_ctx.pop();
continue; }
_ => return Ok(token),
}
}
}
fn advance(&mut self) -> Result<Token> {
let next = self.inner_next_token()?;
let old = std::mem::replace(&mut self.current, next);
Ok(old)
}
pub fn make_node_info(&self, loc: SourceLocation) -> NodeInfo {
match self.macro_ctx.build_macro_info(self.source.interner()) {
Some(macro_info) => NodeInfo::with_macro_info(loc, macro_info),
None => NodeInfo::new(loc),
}
}
pub fn is_in_macro(&self) -> bool {
self.macro_ctx.is_in_macro()
}
pub fn macro_depth(&self) -> usize {
self.macro_ctx.depth()
}
fn expect(&mut self, kind: &TokenKind) -> Result<Token> {
if self.check(kind) {
self.advance()
} else {
Err(CompileError::Parse {
loc: self.current.loc.clone(),
kind: ParseError::UnexpectedToken {
expected: format!("{:?}", kind),
found: self.current.kind.clone(),
},
})
}
}
fn expect_ident(&mut self) -> Result<InternedStr> {
if let TokenKind::Ident(id) = self.current.kind {
self.advance()?;
Ok(id)
} else {
Err(CompileError::Parse {
loc: self.current.loc.clone(),
kind: ParseError::UnexpectedToken {
expected: "identifier".to_string(),
found: self.current.kind.clone(),
},
})
}
}
fn check(&self, kind: &TokenKind) -> bool {
std::mem::discriminant(&self.current.kind) == std::mem::discriminant(kind)
}
fn is_eof(&self) -> bool {
matches!(self.current.kind, TokenKind::Eof)
}
fn current_ident(&self) -> Option<InternedStr> {
if let TokenKind::Ident(id) = self.current.kind {
Some(id)
} else {
None
}
}
fn is_type_arg_builtin(&self, name: InternedStr) -> bool {
let s = self.source.interner().get(name);
matches!(s, "offsetof" | "__builtin_offsetof"
| "__builtin_types_compatible_p"
| "__builtin_va_arg"
| "STRUCT_OFFSET")
}
fn parse_builtin_args(&mut self) -> Result<Vec<BuiltinArg>> {
let mut args = Vec::new();
if !self.check(&TokenKind::RParen) {
loop {
if self.is_type_start() {
let type_name = self.parse_type_name()?;
args.push(BuiltinArg::TypeName(Box::new(type_name)));
} else {
let expr = self.parse_assignment_expr()?;
args.push(BuiltinArg::Expr(Box::new(expr)));
}
if !self.check(&TokenKind::Comma) {
break;
}
self.advance()?;
}
}
Ok(args)
}
fn is_type_start(&self) -> bool {
match &self.current.kind {
TokenKind::KwVoid
| TokenKind::KwChar
| TokenKind::KwShort
| TokenKind::KwInt
| TokenKind::KwLong
| TokenKind::KwFloat
| TokenKind::KwDouble
| TokenKind::KwSigned
| TokenKind::KwSigned2
| TokenKind::KwUnsigned
| TokenKind::KwBool
| TokenKind::KwBool2
| TokenKind::KwComplex
| TokenKind::KwFloat16
| TokenKind::KwFloat32
| TokenKind::KwFloat64
| TokenKind::KwFloat128
| TokenKind::KwFloat32x
| TokenKind::KwFloat64x
| TokenKind::KwInt128 => true,
TokenKind::KwConst
| TokenKind::KwConst2
| TokenKind::KwConst3
| TokenKind::KwVolatile
| TokenKind::KwVolatile2
| TokenKind::KwVolatile3
| TokenKind::KwRestrict
| TokenKind::KwRestrict2
| TokenKind::KwRestrict3
| TokenKind::KwAtomic => true,
TokenKind::KwStruct | TokenKind::KwUnion | TokenKind::KwEnum => true,
TokenKind::KwTypeof | TokenKind::KwTypeof2 | TokenKind::KwTypeof3 => true,
TokenKind::Ident(id) => {
self.typedefs.contains(id) || self.detected_type_params.contains(id)
}
_ => false,
}
}
fn is_declaration_start(&self) -> bool {
match &self.current.kind {
TokenKind::KwTypedef
| TokenKind::KwExtern
| TokenKind::KwStatic
| TokenKind::KwAuto
| TokenKind::KwRegister => true,
TokenKind::KwInline | TokenKind::KwInline2 | TokenKind::KwInline3 => true,
TokenKind::KwExtension => true,
TokenKind::KwThreadLocal | TokenKind::KwThread => true,
_ => self.is_type_start(),
}
}
fn try_skip_attribute(&mut self) -> Result<()> {
loop {
match &self.current.kind {
TokenKind::KwAttribute | TokenKind::KwAttribute2 => {
self.skip_attribute()?;
}
TokenKind::KwAsm | TokenKind::KwAsm2 | TokenKind::KwAsm3 => {
self.try_skip_asm_label()?;
}
_ => break,
}
}
Ok(())
}
fn skip_attribute(&mut self) -> Result<()> {
self.advance()?;
if !self.check(&TokenKind::LParen) {
return Ok(()); }
self.advance()?;
if !self.check(&TokenKind::LParen) {
self.skip_balanced_parens()?;
return Ok(());
}
self.advance()?;
self.skip_balanced_parens()?;
self.expect(&TokenKind::RParen)?;
Ok(())
}
fn try_skip_asm_label(&mut self) -> Result<()> {
if matches!(
self.current.kind,
TokenKind::KwAsm | TokenKind::KwAsm2 | TokenKind::KwAsm3
) {
self.advance()?; if self.check(&TokenKind::LParen) {
self.advance()?; self.skip_balanced_parens()?; }
}
Ok(())
}
fn skip_balanced_parens(&mut self) -> Result<()> {
let mut depth = 1;
while depth > 0 {
match &self.current.kind {
TokenKind::LParen => depth += 1,
TokenKind::RParen => depth -= 1,
TokenKind::Eof => {
return Err(CompileError::Parse {
loc: self.current.loc.clone(),
kind: ParseError::UnexpectedToken {
expected: ")".to_string(),
found: TokenKind::Eof,
},
});
}
_ => {}
}
if depth > 0 {
self.advance()?;
}
}
self.advance()?; Ok(())
}
}
use crate::source::FileRegistry;
use crate::token_source::TokenSlice;
pub fn parse_expression_from_tokens(
tokens: Vec<Token>,
interner: StringInterner,
files: FileRegistry,
typedefs: HashSet<InternedStr>,
) -> Result<Expr> {
let mut source = TokenSlice::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs)?;
parser.parse_expr_only()
}
pub fn parse_expression_from_tokens_ref(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<Expr> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.parse_expr_only()
}
pub fn parse_statement_from_tokens_ref(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<Stmt> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.parse_stmt_allow_missing_semi()
}
#[derive(Debug, Clone, Default)]
pub struct ParseStats {
pub function_call_count: usize,
pub deref_count: usize,
}
impl ParseStats {
pub fn has_unsafe_ops(&self) -> bool {
self.function_call_count > 0 || self.deref_count > 0
}
}
pub fn parse_expression_from_tokens_ref_with_stats(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<(Expr, ParseStats)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
let expr = parser.parse_expr_only()?;
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
Ok((expr, stats))
}
pub fn parse_expression_from_tokens_ref_with_generic_params(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
generic_params: HashMap<InternedStr, usize>,
) -> Result<(Expr, ParseStats, HashSet<InternedStr>)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.generic_params = generic_params;
let expr = parser.parse_expr_only()?;
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
let detected = parser.detected_type_params;
Ok((expr, stats, detected))
}
pub fn parse_statement_from_tokens_ref_with_stats(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<(Stmt, ParseStats)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
let stmt = parser.parse_stmt_allow_missing_semi()?;
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
Ok((stmt, stats))
}
pub fn parse_statement_from_tokens_ref_with_generic_params(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
generic_params: HashMap<InternedStr, usize>,
) -> Result<(Stmt, ParseStats, HashSet<InternedStr>)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.generic_params = generic_params;
let stmt = parser.parse_stmt_allow_missing_semi()?;
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
let detected = parser.detected_type_params;
Ok((stmt, stats, detected))
}
pub fn parse_block_items_from_tokens_ref_with_stats(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<(Vec<BlockItem>, ParseStats)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.allow_missing_semi = true;
let mut items = Vec::new();
while !parser.check(&TokenKind::Eof) {
items.push(parser.parse_block_item()?);
}
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
Ok((items, stats))
}
pub fn parse_block_items_from_tokens_ref_with_generic_params(
tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
generic_params: HashMap<InternedStr, usize>,
) -> Result<(Vec<BlockItem>, ParseStats, HashSet<InternedStr>)> {
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.allow_missing_semi = true;
parser.generic_params = generic_params;
let mut items = Vec::new();
while !parser.check(&TokenKind::Eof) {
items.push(parser.parse_block_item()?);
}
let stats = ParseStats {
function_call_count: parser.function_call_count,
deref_count: parser.deref_count,
};
let detected = parser.detected_type_params;
Ok((items, stats, detected))
}
pub fn parse_type_from_string(
type_str: &str,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<TypeName> {
let file_id = FileId::default();
let mut lexer = Lexer::<LookupOnly>::new_readonly(type_str.as_bytes(), file_id, interner);
let mut tokens = Vec::new();
loop {
let token = lexer.next_token()?;
if matches!(token.kind, TokenKind::Eof) {
break;
}
tokens.push(token);
}
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
parser.parse_type_name()
}
pub fn parse_struct_members_from_tokens_ref(
mut tokens: Vec<Token>,
interner: &StringInterner,
files: &FileRegistry,
typedefs: &HashSet<InternedStr>,
) -> Result<Vec<StructMember>> {
let needs_trailing_semi = tokens
.iter()
.rev()
.find(|t| !matches!(t.kind, TokenKind::Eof))
.is_some_and(|t| !matches!(t.kind, TokenKind::Semi));
if needs_trailing_semi {
let eof = tokens.iter().position(|t| matches!(t.kind, TokenKind::Eof))
.map(|i| tokens.remove(i));
let semi_loc = tokens.last().map(|t| t.loc.clone()).unwrap_or_default();
tokens.push(Token::new(TokenKind::Semi, semi_loc));
if let Some(eof) = eof {
tokens.push(eof);
}
}
let mut source = TokenSliceRef::new(tokens, interner, files);
let mut parser = Parser::from_source_with_typedefs(&mut source, typedefs.clone())?;
let mut members = Vec::new();
while !parser.check(&TokenKind::Eof) {
members.push(parser.parse_struct_member()?);
}
Ok(members)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::preprocessor::PPConfig;
use std::io::Write;
use tempfile::NamedTempFile;
fn parse_str(code: &str) -> Result<TranslationUnit> {
let mut file = NamedTempFile::new().unwrap();
file.write_all(code.as_bytes()).unwrap();
let mut pp = Preprocessor::new(PPConfig::default());
pp.add_source_file(file.path())?;
let mut parser = Parser::new(&mut pp)?;
parser.parse()
}
#[test]
fn test_simple_function() {
let tu = parse_str("int main(void) { return 0; }").unwrap();
assert_eq!(tu.decls.len(), 1);
assert!(matches!(tu.decls[0], ExternalDecl::FunctionDef(_)));
}
#[test]
fn test_variable_declaration() {
let tu = parse_str("int x;").unwrap();
assert_eq!(tu.decls.len(), 1);
assert!(matches!(tu.decls[0], ExternalDecl::Declaration(_)));
}
#[test]
fn test_struct_declaration() {
let tu = parse_str("struct Point { int x; int y; };").unwrap();
assert_eq!(tu.decls.len(), 1);
}
#[test]
fn test_typedef() {
let tu = parse_str("typedef int INT; INT x;").unwrap();
assert_eq!(tu.decls.len(), 2);
}
#[test]
fn test_expression() {
let tu = parse_str("int x = 1 + 2 * 3;").unwrap();
assert_eq!(tu.decls.len(), 1);
}
}