use crate::clang::token::{SourceLoc, Token, TokenKind};
use crate::clang::CLangStandard;
use std::collections::HashSet;
use std::fmt;
pub struct X86ParserDeep {
pub tokens: Vec<Token>,
pub pos: usize,
pub standard: CLangStandard,
pub cpp_mode: bool,
pub gnu_mode: bool,
pub ms_mode: bool,
pub errors: Vec<ParseError>,
pub tu: TranslationUnit,
pub typedef_names: HashSet<String>,
pub tag_names: HashSet<String>,
pub namespace_stack: Vec<String>,
pub template_param_stack: Vec<Vec<TemplateParam>>,
pub in_template_params: bool,
pub current_access: AccessSpecifier,
pub in_class_body: bool,
pub requires_expr_depth: u32,
pub in_coroutine: bool,
pub module_decl: Option<ModuleDeclaration>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError {
pub message: String,
pub location: SourceLoc,
pub is_fatal: bool,
}
impl ParseError {
pub fn new(message: impl Into<String>, location: SourceLoc) -> Self {
Self {
message: message.into(),
location,
is_fatal: false,
}
}
pub fn fatal(message: impl Into<String>, location: SourceLoc) -> Self {
Self {
message: message.into(),
location,
is_fatal: true,
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.location, self.message)
}
}
impl X86ParserDeep {
pub fn new(tokens: Vec<Token>, standard: CLangStandard) -> Self {
let cpp_mode = false;
let gnu_mode = standard.is_gnu();
Self {
tokens,
pos: 0,
standard,
cpp_mode,
gnu_mode,
ms_mode: false,
errors: Vec::new(),
tu: TranslationUnit::default(),
typedef_names: HashSet::new(),
tag_names: HashSet::new(),
namespace_stack: Vec::new(),
template_param_stack: Vec::new(),
in_template_params: false,
current_access: AccessSpecifier::Public,
in_class_body: false,
requires_expr_depth: 0,
in_coroutine: false,
module_decl: None,
}
}
pub fn new_cpp(tokens: Vec<Token>, standard: CLangStandard) -> Self {
let mut p = Self::new(tokens, standard);
p.cpp_mode = true;
p
}
pub fn new_gnu(tokens: Vec<Token>, standard: CLangStandard) -> Self {
let mut p = Self::new(tokens, standard);
p.gnu_mode = true;
p
}
pub fn new_ms(tokens: Vec<Token>, standard: CLangStandard) -> Self {
let mut p = Self::new(tokens, standard);
p.ms_mode = true;
p
}
fn peek(&self) -> Option<&Token> {
let skip: &[TokenKind] = &[];
let mut i = self.pos;
while i < self.tokens.len() {
if skip.contains(&self.tokens[i].kind) {
i += 1;
continue;
}
return Some(&self.tokens[i]);
}
None
}
fn peek_raw(&self) -> Option<&Token> {
self.tokens.get(self.pos)
}
fn peek_n(&self, n: usize) -> Option<&Token> {
let mut i = self.pos;
let mut skipped = 0;
while i < self.tokens.len() && skipped < n {
i += 1;
skipped += 1;
}
self.tokens.get(i)
}
fn peek_kind(&self) -> Option<&TokenKind> {
self.peek().map(|t| &t.kind)
}
fn current(&self) -> Option<&Token> {
self.peek()
}
fn advance(&mut self) -> Option<Token> {
if self.pos < self.tokens.len() {
let t = self.tokens[self.pos].clone();
self.pos += 1;
Some(t)
} else {
None
}
}
fn advance_expected(&mut self, expected: &str) -> Option<Token> {
let loc = self.peek().map(|t| t.location).unwrap_or_default();
let token = self.advance();
if token.is_none() {
self.error(format!("expected {}, found end of file", expected), loc);
}
token
}
fn expect(&mut self, kind: TokenKind) -> Result<Token, ()> {
match self.peek() {
Some(t) if t.kind == kind => Ok(self.advance().unwrap()),
Some(t) => {
let loc = t.location;
self.error(format!("expected {}, found {}", kind.name(), t), loc);
Err(())
}
None => {
self.error(
format!("expected {}, found end of file", kind.name()),
SourceLoc::default(),
);
Err(())
}
}
}
fn expect_any(&mut self, kinds: &[TokenKind]) -> Result<Token, ()> {
match self.peek() {
Some(t) if kinds.contains(&t.kind) => Ok(self.advance().unwrap()),
Some(t) => {
self.error(
format!("expected one of {:?}, found {}", kinds, t),
t.location,
);
Err(())
}
None => Err(()),
}
}
fn match_token(&mut self, kind: TokenKind) -> bool {
if self.peek().map(|t| t.kind == kind).unwrap_or(false) {
self.advance();
true
} else {
false
}
}
fn match_any(&mut self, kinds: &[TokenKind]) -> Option<Token> {
if self
.peek()
.map(|t| kinds.contains(&t.kind))
.unwrap_or(false)
{
self.advance()
} else {
None
}
}
fn is_eof(&self) -> bool {
self.pos >= self.tokens.len() || self.tokens[self.pos].is_eof()
}
fn error(&mut self, msg: impl Into<String>, loc: SourceLoc) {
self.errors.push(ParseError::new(msg, loc));
}
fn fatal_error(&mut self, msg: impl Into<String>, loc: SourceLoc) {
self.errors.push(ParseError::fatal(msg, loc));
}
pub fn parse(&mut self) -> TranslationUnit {
self.tu = TranslationUnit::default();
while !self.is_eof() {
if let Some(decl) = self.parse_external_declaration() {
self.tu.declarations.push(decl);
}
}
self.tu.clone()
}
fn parse_external_declaration(&mut self) -> Option<Declaration> {
if self.match_token(TokenKind::Semicolon) {
return None;
}
if self.cpp_mode && self.at_module_declaration() {
return self.parse_module_declaration();
}
if self.cpp_mode && self.match_token(TokenKind::KwExport) {
return self.parse_export_declaration();
}
if self.cpp_mode {
if let Some(kind) = self.peek_kind() {
if *kind == TokenKind::KwNamespace {
return self.parse_namespace();
}
}
}
if self.cpp_mode {
if let Some(kind) = self.peek_kind() {
if *kind == TokenKind::KwTemplate {
return self.parse_template_declaration();
}
}
}
if self.cpp_mode && self.at_concept_definition() {
return self.parse_concept_definition();
}
self.parse_declaration_or_function()
}
fn parse_declaration_or_function(&mut self) -> Option<Declaration> {
let saved = self.save_state();
let specifiers = self.parse_decl_specifiers();
if specifiers.is_empty() {
self.restore_state(saved);
return self
.parse_statement()
.map(|stmt| Declaration::Statement(Box::new(stmt)));
}
if self.gnu_mode {
if let Some(kind) = self.peek_kind() {
if *kind == TokenKind::KwExtension {
self.advance();
}
}
}
if self.ms_mode {
self.skip_ms_declspec();
}
let mut declarators: Vec<Declarator> = Vec::new();
loop {
if self.match_token(TokenKind::Semicolon) {
return self.build_declaration(specifiers.clone(), declarators);
}
if let Some(decl) = self.parse_declarator() {
declarators.push(decl);
} else {
self.skip_to(TokenKind::Semicolon);
self.advance(); return self.build_declaration(specifiers, declarators);
}
if self.match_token(TokenKind::Equal) {
if let Some(init) = self.parse_assignment_expression() {
if let Some(last) = declarators.last_mut() {
last.initializer = Some(Box::new(init));
}
}
}
if self
.peek()
.map(|t| t.kind == TokenKind::LBrace)
.unwrap_or(false)
{
if let Some(last) = declarators.last() {
let name = last.name.clone();
let params = last.params.clone();
let body = self.parse_compound_statement();
return Some(Declaration::Function(FunctionDecl {
name,
return_type: Type::from_specifiers(&specifiers),
params: params.unwrap_or_default(),
body: Some(Box::new(body)),
is_definition: true,
specifiers: specifiers,
attributes: vec![],
}));
}
}
if self.match_token(TokenKind::Comma) {
continue;
} else {
break;
}
}
self.match_token(TokenKind::Semicolon);
self.build_declaration(specifiers, declarators)
}
fn build_declaration(
&self,
specifiers: Vec<DeclSpecifier>,
declarators: Vec<Declarator>,
) -> Option<Declaration> {
if declarators.is_empty() {
for spec in &specifiers {
match spec {
DeclSpecifier::Struct(name) => {
return Some(Declaration::Struct(StructDecl {
name: name.clone(),
fields: vec![],
}));
}
DeclSpecifier::Union(name) => {
return Some(Declaration::Union(UnionDecl {
name: name.clone(),
fields: vec![],
}));
}
DeclSpecifier::Enum(name) => {
return Some(Declaration::Enum(EnumDecl {
name: name.clone(),
enumerators: vec![],
}));
}
_ => {}
}
}
return None;
}
let mut decls = Vec::new();
for d in declarators {
let ty = Type::from_specifiers(&specifiers);
let var = VarDecl {
name: d.name,
var_type: ty,
initializer: d.initializer,
specifiers: specifiers.clone(),
};
decls.push(Declaration::Variable(var));
}
if decls.len() == 1 {
Some(decls.into_iter().next().unwrap())
} else {
Some(Declaration::DeclList(decls))
}
}
fn parse_decl_specifiers(&mut self) -> Vec<DeclSpecifier> {
let mut specs = Vec::new();
let mut has_type = false;
let mut has_tag = false;
loop {
match self.peek_kind() {
Some(TokenKind::KwTypedef) => {
specs.push(DeclSpecifier::Typedef);
self.advance();
}
Some(TokenKind::KwExtern) => {
specs.push(DeclSpecifier::Extern);
self.advance();
}
Some(TokenKind::KwStatic) => {
specs.push(DeclSpecifier::Static);
self.advance();
}
Some(TokenKind::KwAuto) => {
specs.push(DeclSpecifier::Auto);
self.advance();
}
Some(TokenKind::KwRegister) => {
specs.push(DeclSpecifier::Register);
self.advance();
}
Some(TokenKind::KwMutable) if self.cpp_mode => {
specs.push(DeclSpecifier::Mutable);
self.advance();
}
Some(TokenKind::KwThreadLocal) => {
specs.push(DeclSpecifier::ThreadLocal);
self.advance();
}
Some(TokenKind::KwConstexpr) if self.cpp_mode => {
specs.push(DeclSpecifier::Constexpr);
self.advance();
}
Some(TokenKind::KwConst) => {
specs.push(DeclSpecifier::Const);
self.advance();
}
Some(TokenKind::KwVolatile) => {
specs.push(DeclSpecifier::Volatile);
self.advance();
}
Some(TokenKind::KwRestrict) => {
specs.push(DeclSpecifier::Restrict);
self.advance();
}
Some(TokenKind::KwInt) => {
specs.push(DeclSpecifier::Type("int".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwChar) => {
specs.push(DeclSpecifier::Type("char".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwShort) => {
specs.push(DeclSpecifier::Type("short".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwLong) => {
specs.push(DeclSpecifier::Type("long".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwFloat) => {
specs.push(DeclSpecifier::Type("float".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwDouble) => {
specs.push(DeclSpecifier::Type("double".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwSigned) => {
specs.push(DeclSpecifier::Type("signed".into()));
self.advance();
}
Some(TokenKind::KwUnsigned) => {
specs.push(DeclSpecifier::Type("unsigned".into()));
self.advance();
}
Some(TokenKind::KwVoid) => {
specs.push(DeclSpecifier::Type("void".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwBool) => {
specs.push(DeclSpecifier::Type("_Bool".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwComplex) => {
specs.push(DeclSpecifier::Type("_Complex".into()));
self.advance();
}
Some(TokenKind::KwAtomic) => {
specs.push(DeclSpecifier::Type("_Atomic".into()));
self.advance();
}
Some(TokenKind::KwWcharT) if self.cpp_mode => {
specs.push(DeclSpecifier::Type("wchar_t".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwChar16T) if self.cpp_mode => {
specs.push(DeclSpecifier::Type("char16_t".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwChar32T) if self.cpp_mode => {
specs.push(DeclSpecifier::Type("char32_t".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwChar8T) if self.cpp_mode => {
specs.push(DeclSpecifier::Type("char8_t".into()));
self.advance();
has_type = true;
}
Some(TokenKind::KwStruct) => {
self.advance();
has_tag = true;
if let Some(parsed) = self.parse_struct_or_class(true) {
specs.push(parsed);
}
}
Some(TokenKind::KwUnion) => {
self.advance();
has_tag = true;
if let Some(parsed) = self.parse_union() {
specs.push(parsed);
}
}
Some(TokenKind::KwEnum) => {
self.advance();
has_tag = true;
if let Some(parsed) = self.parse_enum() {
specs.push(parsed);
}
}
Some(TokenKind::KwClass) if self.cpp_mode => {
self.advance();
has_tag = true;
if let Some(parsed) = self.parse_struct_or_class(false) {
specs.push(parsed);
}
}
Some(TokenKind::KwAttribute) if self.gnu_mode => {
self.advance();
self.parse_gnu_attribute();
}
Some(TokenKind::Identifier) => {
let ident = self.peek().unwrap().text.clone();
if self.typedef_names.contains(&ident) {
specs.push(DeclSpecifier::Type(ident));
self.advance();
has_type = true;
} else if has_type && !has_tag {
break;
} else {
break;
}
}
_ => break,
}
}
specs
}
fn parse_declarator(&mut self) -> Option<Declarator> {
let mut ptr_depth = 0;
while self.match_token(TokenKind::Star) {
ptr_depth += 1;
while self
.peek_kind()
.map(|k| {
*k == TokenKind::KwConst
|| *k == TokenKind::KwVolatile
|| *k == TokenKind::KwRestrict
})
.unwrap_or(false)
{
self.advance();
}
}
if self.cpp_mode && self.match_token(TokenKind::Ampersand) {
ptr_depth += 1;
if self.match_token(TokenKind::Ampersand) {
ptr_depth += 1;
}
}
if self.cpp_mode {
let saved = self.save_state();
if let Some(_ident) = self.parse_identifier() {
if self.match_token(TokenKind::ScopeResolution) {
if self.match_token(TokenKind::Star) {
ptr_depth += 1;
}
} else {
self.restore_state(saved);
}
}
}
let (name, params, array_size) = self.parse_direct_declarator()?;
let mut asm_label = None;
if self.gnu_mode && self.peek_kind() == Some(&TokenKind::KwAsm) {
self.advance();
if self.match_token(TokenKind::LParen) {
if let Some(tok) = self.advance() {
if tok.kind == TokenKind::StringLiteral {
asm_label = Some(tok.text);
}
}
self.match_token(TokenKind::RParen);
}
}
let member_init = None;
if self.cpp_mode && self.match_token(TokenKind::Colon) {
}
if self.cpp_mode {
while self
.peek_kind()
.map(|k| {
*k == TokenKind::KwConst
|| *k == TokenKind::KwVolatile
|| *k == TokenKind::KwRestrict
})
.unwrap_or(false)
{
self.advance();
}
if self.peek_kind() == Some(&TokenKind::Ampersand) {
self.advance();
self.match_token(TokenKind::Ampersand); }
}
if self.cpp_mode {
self.match_token(TokenKind::KwNoexcept);
if self.match_token(TokenKind::LParen) {
self.parse_expression();
self.match_token(TokenKind::RParen);
}
}
if self.cpp_mode {
if let Some(tok) = self.peek() {
if tok.text == "override" || tok.text == "final" {
self.advance();
}
}
}
if self.cpp_mode && self.peek_kind() == Some(&TokenKind::KwRequires) {
self.parse_requires_clause();
}
Some(Declarator {
name,
params,
ptr_depth,
array_size,
initializer: None,
asm_label,
member_init,
})
}
fn parse_direct_declarator(
&mut self,
) -> Option<(String, Option<Vec<ParamDecl>>, Option<Expr>)> {
let mut name = String::new();
let mut params = None;
let mut array_size = None;
if self.match_token(TokenKind::LParen) {
let inner = self.parse_declarator();
self.match_token(TokenKind::RParen);
if let Some(inner) = inner {
name = inner.name;
}
}
if name.is_empty() {
if let Some(tok) = self.peek() {
if tok.kind == TokenKind::Identifier {
name = tok.text.clone();
self.advance();
}
}
}
while self.match_token(TokenKind::LBracket) {
if !self.match_token(TokenKind::RBracket) {
array_size = self.parse_expression();
self.match_token(TokenKind::RBracket);
}
if self.match_token(TokenKind::KwStatic) {
self.parse_expression();
}
}
if self.match_token(TokenKind::LParen) {
if !self.match_token(TokenKind::RParen) {
params = Some(self.parse_parameter_list());
self.match_token(TokenKind::RParen);
} else {
params = Some(vec![]);
}
}
Some((name, params, array_size))
}
fn parse_parameter_list(&mut self) -> Vec<ParamDecl> {
let mut params = Vec::new();
if self.match_token(TokenKind::Ellipsis) {
params.push(ParamDecl {
name: "...".into(),
param_type: Type::Void,
default_value: None,
});
return params;
}
loop {
let specs = self.parse_decl_specifiers();
let decl = self.parse_declarator();
let name = decl.as_ref().map(|d| d.name.clone()).unwrap_or_default();
let param_type = Type::from_specifiers(&specs);
let default_value = None;
params.push(ParamDecl {
name,
param_type,
default_value,
});
if self.match_token(TokenKind::Comma) {
if self.match_token(TokenKind::Ellipsis) {
params.push(ParamDecl {
name: "...".into(),
param_type: Type::Void,
default_value: None,
});
break;
}
continue;
}
break;
}
params
}
fn parse_statement(&mut self) -> Option<Stmt> {
match self.peek_kind() {
Some(TokenKind::LBrace) => Some(self.parse_compound_statement()),
Some(TokenKind::KwIf) => Some(self.parse_if_statement()),
Some(TokenKind::KwSwitch) => Some(self.parse_switch_statement()),
Some(TokenKind::KwWhile) => Some(self.parse_while_statement()),
Some(TokenKind::KwDo) => Some(self.parse_do_while_statement()),
Some(TokenKind::KwFor) => Some(self.parse_for_statement()),
Some(TokenKind::KwReturn) => Some(self.parse_return_statement()),
Some(TokenKind::KwBreak) => {
self.advance();
self.match_token(TokenKind::Semicolon);
Some(Stmt::Break)
}
Some(TokenKind::KwContinue) => {
self.advance();
self.match_token(TokenKind::Semicolon);
Some(Stmt::Continue)
}
Some(TokenKind::KwGoto) => self.parse_goto_statement(),
Some(TokenKind::KwCase) => self.parse_case_statement(),
Some(TokenKind::KwDefault) => self.parse_default_statement(),
Some(TokenKind::Semicolon) => {
self.advance();
Some(Stmt::Empty)
}
Some(TokenKind::KwTry) if self.cpp_mode => self.parse_try_statement(),
Some(TokenKind::KwCoReturn) if self.cpp_mode => self.parse_coreturn_statement(),
Some(TokenKind::KwCoYield) if self.cpp_mode => self.parse_coyield_statement(),
Some(TokenKind::Identifier) => {
let saved = self.save_state();
let _ident = self.advance().unwrap();
if self.match_token(TokenKind::Colon) {
return Some(Stmt::Labeled {
label: _ident.text,
stmt: Box::new(self.parse_statement()?),
});
}
self.restore_state(saved);
Some(self.parse_expression_statement())
}
_ => {
Some(self.parse_expression_statement())
}
}
}
fn parse_compound_statement(&mut self) -> Stmt {
self.expect(TokenKind::LBrace).ok();
let mut stmts = Vec::new();
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
if self.is_at_declaration_start() {
if let Some(decl) = self.parse_declaration_or_function() {
stmts.push(Stmt::Declaration(Box::new(decl)));
continue;
}
}
if let Some(stmt) = self.parse_statement() {
stmts.push(stmt);
} else {
self.skip_to_recovery_point();
if self.peek_kind() == Some(&TokenKind::RBrace) {
break;
}
}
}
self.expect(TokenKind::RBrace).ok();
Stmt::Compound(stmts)
}
fn parse_expression_statement(&mut self) -> Stmt {
let expr = self.parse_expression();
self.match_token(TokenKind::Semicolon);
Stmt::Expr(expr.map(Box::new))
}
fn parse_if_statement(&mut self) -> Stmt {
self.advance(); let _is_constexpr = self.cpp_mode && self.match_token(TokenKind::KwConstexpr);
if self.cpp_mode && self.match_token(TokenKind::LParen) {
}
self.expect(TokenKind::LParen).ok();
let cond = self.parse_expression();
self.expect(TokenKind::RParen).ok();
let then_branch = Box::new(self.parse_statement().unwrap_or(Stmt::Empty));
let else_branch = if self.match_token(TokenKind::KwElse) {
Some(Box::new(self.parse_statement().unwrap_or(Stmt::Empty)))
} else {
None
};
Stmt::If {
cond: cond.map(Box::new),
then_branch,
else_branch,
}
}
fn parse_while_statement(&mut self) -> Stmt {
self.advance(); self.expect(TokenKind::LParen).ok();
let cond = self.parse_expression();
self.expect(TokenKind::RParen).ok();
let body = Box::new(self.parse_statement().unwrap_or(Stmt::Empty));
Stmt::While {
cond: cond.map(Box::new),
body,
}
}
fn parse_do_while_statement(&mut self) -> Stmt {
self.advance(); let body = Box::new(self.parse_statement().unwrap_or(Stmt::Empty));
self.expect(TokenKind::KwWhile).ok();
self.expect(TokenKind::LParen).ok();
let cond = self.parse_expression();
self.expect(TokenKind::RParen).ok();
self.match_token(TokenKind::Semicolon);
Stmt::DoWhile {
body,
cond: cond.map(Box::new),
}
}
fn parse_for_statement(&mut self) -> Stmt {
self.advance(); self.expect(TokenKind::LParen).ok();
let init = if self.is_at_declaration_start() {
let decl = self.parse_declaration_or_function();
Stmt::Declaration(
decl.map(Box::new)
.unwrap_or_else(|| Box::new(Declaration::Empty)),
)
} else {
let expr = self.parse_expression();
self.match_token(TokenKind::Semicolon);
Stmt::Expr(expr.map(Box::new))
};
let cond = self.parse_expression();
self.match_token(TokenKind::Semicolon);
let incr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
let body = Box::new(self.parse_statement().unwrap_or(Stmt::Empty));
Stmt::For {
init: Some(Box::new(init)),
cond: cond.map(Box::new),
incr: incr.map(Box::new),
body,
}
}
fn parse_switch_statement(&mut self) -> Stmt {
self.advance(); self.expect(TokenKind::LParen).ok();
let expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
let body = Box::new(self.parse_statement().unwrap_or(Stmt::Empty));
Stmt::Switch {
expr: expr.map(Box::new),
body,
}
}
fn parse_return_statement(&mut self) -> Stmt {
self.advance(); let expr = if self.peek_kind() != Some(&TokenKind::Semicolon) {
self.parse_expression()
} else {
None
};
self.match_token(TokenKind::Semicolon);
Stmt::Return(expr.map(Box::new))
}
fn parse_goto_statement(&mut self) -> Option<Stmt> {
self.advance(); let label = self.advance()?.text;
self.match_token(TokenKind::Semicolon);
Some(Stmt::Goto(label))
}
fn parse_case_statement(&mut self) -> Option<Stmt> {
self.advance(); let expr = self.parse_expression()?;
let end = if self.gnu_mode && self.peek().map(|t| t.text == "...").unwrap_or(false) {
self.advance();
self.parse_expression()
} else {
None
};
self.expect(TokenKind::Colon).ok();
let stmt = Box::new(self.parse_statement()?);
Some(Stmt::Case {
expr: Box::new(expr),
end: end.map(Box::new),
stmt,
})
}
fn parse_default_statement(&mut self) -> Option<Stmt> {
self.advance(); self.expect(TokenKind::Colon).ok();
Some(Stmt::Default(Box::new(self.parse_statement()?)))
}
fn parse_try_statement(&mut self) -> Option<Stmt> {
self.advance(); let body = self.parse_compound_statement();
let mut handlers = Vec::new();
self.expect(TokenKind::KwCatch).ok();
self.expect(TokenKind::LParen).ok();
let _exc_decl = self.parse_declaration_or_function();
self.expect(TokenKind::RParen).ok();
let handler_body = self.parse_compound_statement();
handlers.push(handler_body);
while self.peek_kind() == Some(&TokenKind::KwCatch) {
self.advance();
self.expect(TokenKind::LParen).ok();
self.parse_declaration_or_function();
self.expect(TokenKind::RParen).ok();
handlers.push(self.parse_compound_statement());
}
Some(Stmt::Try {
body: Box::new(body),
handlers,
})
}
fn parse_coreturn_statement(&mut self) -> Option<Stmt> {
self.advance(); let expr = if self.peek_kind() != Some(&TokenKind::Semicolon) {
self.parse_expression()
} else {
None
};
self.match_token(TokenKind::Semicolon);
self.in_coroutine = true;
Some(Stmt::CoReturn(expr.map(Box::new)))
}
fn parse_coyield_statement(&mut self) -> Option<Stmt> {
self.advance(); let expr = self.parse_expression()?;
self.match_token(TokenKind::Semicolon);
self.in_coroutine = true;
Some(Stmt::CoYield(Box::new(expr)))
}
pub fn parse_expression(&mut self) -> Option<Expr> {
self.parse_comma_expression()
}
fn parse_comma_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_assignment_expression()?;
while self.match_token(TokenKind::Comma) {
let right = self.parse_assignment_expression()?;
left = Expr::Binary {
op: BinaryOp::Comma,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_assignment_expression(&mut self) -> Option<Expr> {
if self.cpp_mode && self.peek_kind() == Some(&TokenKind::KwThrow) {
return self.parse_throw_expression();
}
let left = self.parse_conditional_expression()?;
let op = match self.peek_kind() {
Some(TokenKind::Equal) => Some(BinaryOp::Assign),
Some(TokenKind::PlusEqual) => Some(BinaryOp::AddAssign),
Some(TokenKind::MinusEqual) => Some(BinaryOp::SubAssign),
Some(TokenKind::StarEqual) => Some(BinaryOp::MulAssign),
Some(TokenKind::SlashEqual) => Some(BinaryOp::DivAssign),
Some(TokenKind::PercentEqual) => Some(BinaryOp::ModAssign),
Some(TokenKind::LessLessEqual) | Some(TokenKind::LeftShiftAssign) => {
Some(BinaryOp::ShlAssign)
}
Some(TokenKind::GreaterGreaterEqual) | Some(TokenKind::RightShiftAssign) => {
Some(BinaryOp::ShrAssign)
}
Some(TokenKind::AmpersandEqual) => Some(BinaryOp::AndAssign),
Some(TokenKind::PipeEqual) => Some(BinaryOp::OrAssign),
Some(TokenKind::CaretEqual) => Some(BinaryOp::XorAssign),
_ => None,
};
if let Some(op) = op {
self.advance();
let right = self.parse_assignment_expression()?;
Some(Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
})
} else {
Some(left)
}
}
fn parse_conditional_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_logical_or_expression()?;
if self.cpp_mode && self.match_token(TokenKind::Spaceship) {
let right = self.parse_logical_or_expression()?;
left = Expr::Binary {
op: BinaryOp::Spaceship,
left: Box::new(left),
right: Box::new(right),
};
}
if self.match_token(TokenKind::Question) {
let then_expr = self.parse_expression()?;
self.expect(TokenKind::Colon).ok();
let else_expr = self.parse_conditional_expression()?;
left = Expr::Conditional {
cond: Box::new(left),
then_expr: Box::new(then_expr),
else_expr: Box::new(else_expr),
};
}
Some(left)
}
fn parse_logical_or_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_logical_and_expression()?;
while self.match_token(TokenKind::OrOr)
|| (self.cpp_mode && self.match_token(TokenKind::KwOr))
{
let right = self.parse_logical_and_expression()?;
left = Expr::Binary {
op: BinaryOp::LogicalOr,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_logical_and_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_inclusive_or_expression()?;
while self.match_token(TokenKind::AndAnd)
|| (self.cpp_mode && self.match_token(TokenKind::KwAnd))
{
let right = self.parse_inclusive_or_expression()?;
left = Expr::Binary {
op: BinaryOp::LogicalAnd,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_inclusive_or_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_exclusive_or_expression()?;
while self.match_token(TokenKind::Pipe)
|| (self.cpp_mode && self.match_token(TokenKind::KwBitor))
{
let right = self.parse_exclusive_or_expression()?;
left = Expr::Binary {
op: BinaryOp::BitOr,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_exclusive_or_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_and_expression()?;
while self.match_token(TokenKind::Caret)
|| (self.cpp_mode && self.match_token(TokenKind::KwXor))
{
let right = self.parse_and_expression()?;
left = Expr::Binary {
op: BinaryOp::BitXor,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_and_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_equality_expression()?;
while self.match_token(TokenKind::Ampersand)
|| (self.cpp_mode && self.match_token(TokenKind::KwBitAnd))
{
let right = self.parse_equality_expression()?;
left = Expr::Binary {
op: BinaryOp::BitAnd,
left: Box::new(left),
right: Box::new(right),
};
}
Some(left)
}
fn parse_equality_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_relational_expression()?;
loop {
let op = if self.match_token(TokenKind::EqualEqual) {
Some(BinaryOp::Eq)
} else if self.match_token(TokenKind::NotEqual)
|| (self.cpp_mode && self.match_token(TokenKind::KwNotEq))
{
Some(BinaryOp::Ne)
} else {
None
};
if let Some(op) = op {
let right = self.parse_relational_expression()?;
left = Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
};
} else {
break;
}
}
Some(left)
}
fn parse_relational_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_shift_expression()?;
loop {
let op = if self.match_token(TokenKind::Less) {
Some(BinaryOp::Lt)
} else if self.match_token(TokenKind::Greater) {
Some(BinaryOp::Gt)
} else if self.match_token(TokenKind::LessEqual) {
Some(BinaryOp::Le)
} else if self.match_token(TokenKind::GreaterEqual) {
Some(BinaryOp::Ge)
} else {
None
};
if let Some(op) = op {
let right = self.parse_shift_expression()?;
left = Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
};
} else {
break;
}
}
Some(left)
}
fn parse_shift_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_additive_expression()?;
loop {
let op = if self.match_token(TokenKind::LessLess) {
Some(BinaryOp::Shl)
} else if self.match_token(TokenKind::GreaterGreater) {
Some(BinaryOp::Shr)
} else {
None
};
if let Some(op) = op {
let right = self.parse_additive_expression()?;
left = Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
};
} else {
break;
}
}
Some(left)
}
fn parse_additive_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_multiplicative_expression()?;
loop {
let op = if self.match_token(TokenKind::Plus) {
Some(BinaryOp::Add)
} else if self.match_token(TokenKind::Minus) {
Some(BinaryOp::Sub)
} else {
None
};
if let Some(op) = op {
let right = self.parse_multiplicative_expression()?;
left = Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
};
} else {
break;
}
}
Some(left)
}
fn parse_multiplicative_expression(&mut self) -> Option<Expr> {
let mut left = self.parse_cxx_cast_expression()?;
loop {
let op = if self.match_token(TokenKind::Star) {
Some(BinaryOp::Mul)
} else if self.match_token(TokenKind::Slash) {
Some(BinaryOp::Div)
} else if self.match_token(TokenKind::Percent) {
Some(BinaryOp::Mod)
} else {
None
};
if let Some(op) = op {
let right = self.parse_cxx_cast_expression()?;
left = Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
};
} else {
break;
}
}
Some(left)
}
fn parse_cxx_cast_expression(&mut self) -> Option<Expr> {
if !self.cpp_mode {
return self.parse_cast_expression();
}
match self.peek_kind() {
Some(TokenKind::KwStaticCast)
| Some(TokenKind::KwDynamicCast)
| Some(TokenKind::KwReinterpretCast)
| Some(TokenKind::KwConstCast) => {
let kind = self.advance().unwrap().kind;
self.expect(TokenKind::Less).ok();
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::Greater).ok();
self.expect(TokenKind::LParen).ok();
let expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
expr.map(|e| Expr::CxxCast {
kind: cxx_cast_kind_from_token(kind),
expr: Box::new(e),
target_type: Type::Int, })
}
_ => self.parse_cast_expression(),
}
}
fn parse_cast_expression(&mut self) -> Option<Expr> {
let saved = self.save_state();
if self.match_token(TokenKind::LParen) {
if self.is_at_type_specifier() {
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::RParen).ok();
let expr = self.parse_cast_expression()?;
return Some(Expr::Cast {
target_type: Type::Int,
expr: Box::new(expr),
});
}
self.restore_state(saved);
}
self.parse_unary_expression()
}
fn parse_unary_expression(&mut self) -> Option<Expr> {
match self.peek_kind() {
Some(TokenKind::PlusPlus) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::PreInc,
expr: Box::new(operand),
});
}
Some(TokenKind::MinusMinus) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::PreDec,
expr: Box::new(operand),
});
}
Some(TokenKind::Plus) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::Plus,
expr: Box::new(operand),
});
}
Some(TokenKind::Minus) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::Minus,
expr: Box::new(operand),
});
}
Some(TokenKind::Exclaim) | Some(TokenKind::KwNot) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::Not,
expr: Box::new(operand),
});
}
Some(TokenKind::Tilde) | Some(TokenKind::KwCompl) => {
self.advance();
let operand = self.parse_unary_expression()?;
return Some(Expr::Unary {
op: UnaryOp::BitNot,
expr: Box::new(operand),
});
}
Some(TokenKind::Star) => {
self.advance();
let operand = self.parse_cast_expression()?;
return Some(Expr::Unary {
op: UnaryOp::Deref,
expr: Box::new(operand),
});
}
Some(TokenKind::Ampersand) => {
self.advance();
let operand = self.parse_cast_expression()?;
return Some(Expr::Unary {
op: UnaryOp::AddrOf,
expr: Box::new(operand),
});
}
Some(TokenKind::KwSizeof) => {
self.advance();
if self.match_token(TokenKind::LParen) {
if self.is_at_type_specifier() {
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::RParen).ok();
return Some(Expr::SizeOf(Box::new(Expr::TypeName(Type::Int))));
} else {
let expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
return Some(Expr::SizeOf(Box::new(expr?)));
}
} else {
let expr = self.parse_unary_expression()?;
return Some(Expr::SizeOf(Box::new(expr)));
}
}
Some(TokenKind::KwAlignof) | Some(TokenKind::KwAlignof2) => {
self.advance();
self.expect(TokenKind::LParen).ok();
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::RParen).ok();
return Some(Expr::AlignOf(Type::Int));
}
Some(TokenKind::KwBuiltinVaArg) if self.gnu_mode => {
return self.parse_builtin_va_arg();
}
Some(TokenKind::KwBuiltinOffsetof) if self.gnu_mode => {
return self.parse_builtin_offsetof();
}
Some(TokenKind::KwNew) if self.cpp_mode => {
return self.parse_new_expression();
}
Some(TokenKind::KwDelete) if self.cpp_mode => {
return self.parse_delete_expression();
}
Some(TokenKind::KwCoAwait) if self.cpp_mode => {
self.advance();
let expr = self.parse_unary_expression()?;
return Some(Expr::CoAwait(Box::new(expr)));
}
_ => {}
}
self.parse_postfix_expression()
}
fn parse_postfix_expression(&mut self) -> Option<Expr> {
let mut expr = self.parse_primary_expression()?;
loop {
match self.peek_kind() {
Some(TokenKind::LBracket) => {
self.advance();
let index = self.parse_expression();
self.expect(TokenKind::RBracket).ok();
expr = Expr::Subscript {
array: Box::new(expr),
index: Box::new(index?),
};
}
Some(TokenKind::LParen) => {
self.advance();
let mut args = Vec::new();
if self.peek_kind() != Some(&TokenKind::RParen) {
loop {
if let Some(arg) = self.parse_assignment_expression() {
args.push(arg);
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
}
self.expect(TokenKind::RParen).ok();
expr = Expr::Call {
callee: Box::new(expr),
args,
};
}
Some(TokenKind::Dot) => {
self.advance();
let member = self.parse_identifier_or_keyword();
expr = Expr::Member {
object: Box::new(expr),
member: member.unwrap_or_default(),
};
}
Some(TokenKind::Arrow) => {
self.advance();
let member = self.parse_identifier_or_keyword();
expr = Expr::Arrow {
object: Box::new(expr),
member: member.unwrap_or_default(),
};
}
Some(TokenKind::PlusPlus) => {
self.advance();
expr = Expr::Unary {
op: UnaryOp::PostInc,
expr: Box::new(expr),
};
}
Some(TokenKind::MinusMinus) => {
self.advance();
expr = Expr::Unary {
op: UnaryOp::PostDec,
expr: Box::new(expr),
};
}
Some(TokenKind::Less) if self.cpp_mode => {
let saved = self.save_state();
self.advance();
if self.parse_template_argument_list().is_some() {
if self.match_token(TokenKind::Greater) {
}
} else {
self.restore_state(saved);
break;
}
}
Some(TokenKind::DotStar) | Some(TokenKind::ArrowStar) if self.cpp_mode => {
self.advance();
let member = self.parse_identifier_or_keyword();
expr = Expr::PtrToMember {
object: Box::new(expr),
member: Box::new(Expr::Ident(member.unwrap_or_default())),
};
}
_ => break,
}
}
Some(expr)
}
fn parse_primary_expression(&mut self) -> Option<Expr> {
match self.peek().map(|t| t.kind) {
Some(TokenKind::Identifier) => {
let ident = self.advance().unwrap().text;
Some(Expr::Ident(ident))
}
Some(TokenKind::NumericLiteral) => {
let num = self.advance().unwrap().text;
Some(Expr::Literal(Literal::Int(num.parse().unwrap_or(0))))
}
Some(TokenKind::CharLiteral) => {
let ch = self.advance().unwrap().text.chars().nth(1).unwrap_or('\0');
Some(Expr::Literal(Literal::Char(ch)))
}
Some(TokenKind::StringLiteral) => {
let s = self.advance().unwrap().text;
Some(Expr::Literal(Literal::String(s)))
}
Some(TokenKind::KwTrue) if self.cpp_mode => {
self.advance();
Some(Expr::Literal(Literal::Bool(true)))
}
Some(TokenKind::KwFalse) if self.cpp_mode => {
self.advance();
Some(Expr::Literal(Literal::Bool(false)))
}
Some(TokenKind::KwNullptr) if self.cpp_mode => {
self.advance();
Some(Expr::NullPtr)
}
Some(TokenKind::KwThis) if self.cpp_mode => {
self.advance();
Some(Expr::This)
}
Some(TokenKind::LParen) => {
self.advance();
if self.cpp_mode && self.match_token(TokenKind::LBracket) {
return self.parse_lambda_expression_after_capture();
}
if self.gnu_mode {
let saved = self.save_state();
if self.peek_kind() == Some(&TokenKind::LBrace) {
self.restore_state(saved);
return self.parse_stmt_expr();
}
self.restore_state(saved);
}
let expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
expr
}
Some(TokenKind::LBracket) if self.cpp_mode => self.parse_lambda_expression(),
Some(TokenKind::KwRequires) if self.cpp_mode => self.parse_requires_expression(),
Some(TokenKind::KwBuiltinChooseExpr) if self.gnu_mode => {
self.parse_builtin_choose_expr()
}
Some(TokenKind::KwBuiltinTypesCompatible) if self.gnu_mode => {
self.parse_builtin_types_compatible()
}
_ => {
if let Some(tok) = self.peek() {
self.error(format!("unexpected token: {}", tok), tok.location);
}
None
}
}
}
fn parse_throw_expression(&mut self) -> Option<Expr> {
self.advance(); let expr = if self.peek_kind() != Some(&TokenKind::Semicolon) {
self.parse_assignment_expression()
} else {
None
};
Some(Expr::Throw(expr.map(Box::new)))
}
fn parse_identifier_or_keyword(&mut self) -> Option<String> {
match self.peek() {
Some(t) if t.kind == TokenKind::Identifier || t.kind.is_keyword() => {
Some(self.advance().unwrap().text)
}
_ => None,
}
}
fn parse_identifier(&mut self) -> Option<String> {
match self.peek() {
Some(t) if t.kind == TokenKind::Identifier => Some(self.advance().unwrap().text),
_ => None,
}
}
fn is_at_type_specifier(&self) -> bool {
match self.peek_kind() {
Some(TokenKind::KwInt)
| Some(TokenKind::KwChar)
| Some(TokenKind::KwShort)
| Some(TokenKind::KwLong)
| Some(TokenKind::KwFloat)
| Some(TokenKind::KwDouble)
| Some(TokenKind::KwSigned)
| Some(TokenKind::KwUnsigned)
| Some(TokenKind::KwVoid)
| Some(TokenKind::KwBool)
| Some(TokenKind::KwStruct)
| Some(TokenKind::KwUnion)
| Some(TokenKind::KwEnum) => true,
Some(TokenKind::KwConst)
| Some(TokenKind::KwVolatile)
| Some(TokenKind::KwRestrict) => true,
Some(TokenKind::Identifier) => {
let ident = self.peek().unwrap().text.clone();
self.typedef_names.contains(&ident)
}
_ => false,
}
}
fn parse_type_specifier_for_cast(&mut self) -> Option<Type> {
let specs = self.parse_decl_specifiers();
Some(Type::from_specifiers(&specs))
}
fn is_at_declaration_start(&self) -> bool {
match self.peek_kind() {
Some(TokenKind::KwInt)
| Some(TokenKind::KwChar)
| Some(TokenKind::KwShort)
| Some(TokenKind::KwLong)
| Some(TokenKind::KwFloat)
| Some(TokenKind::KwDouble)
| Some(TokenKind::KwSigned)
| Some(TokenKind::KwUnsigned)
| Some(TokenKind::KwVoid)
| Some(TokenKind::KwBool)
| Some(TokenKind::KwStruct)
| Some(TokenKind::KwUnion)
| Some(TokenKind::KwEnum)
| Some(TokenKind::KwTypedef)
| Some(TokenKind::KwExtern)
| Some(TokenKind::KwStatic)
| Some(TokenKind::KwConst)
| Some(TokenKind::KwVolatile)
| Some(TokenKind::KwRestrict)
| Some(TokenKind::KwAuto)
| Some(TokenKind::KwRegister)
| Some(TokenKind::KwThreadLocal)
| Some(TokenKind::KwInline) => true,
Some(TokenKind::KwClass)
| Some(TokenKind::KwNamespace)
| Some(TokenKind::KwTemplate)
| Some(TokenKind::KwUsing)
| Some(TokenKind::KwConstexpr)
| Some(TokenKind::KwExport) => self.cpp_mode,
_ => false,
}
}
fn skip_to(&mut self, kind: TokenKind) {
while !self.is_eof() && self.peek_kind() != Some(&kind) {
self.advance();
}
}
fn skip_to_recovery_point(&mut self) {
let sync_tokens = [
TokenKind::Semicolon,
TokenKind::RBrace,
TokenKind::KwIf,
TokenKind::KwWhile,
TokenKind::KwFor,
TokenKind::KwReturn,
TokenKind::KwBreak,
TokenKind::KwContinue,
TokenKind::KwGoto,
];
while !self.is_eof() {
if self
.peek_kind()
.map(|k| sync_tokens.contains(k))
.unwrap_or(false)
{
break;
}
self.advance();
}
}
fn save_state(&self) -> ParseState {
ParseState {
pos: self.pos,
errors_len: self.errors.len(),
}
}
fn restore_state(&mut self, state: ParseState) {
self.pos = state.pos;
self.errors.truncate(state.errors_len);
}
}
#[derive(Debug, Clone)]
pub struct ParseState {
pub pos: usize,
pub errors_len: usize,
}
fn cxx_cast_kind_from_token(kind: TokenKind) -> CxxCastKind {
match kind {
TokenKind::KwStaticCast => CxxCastKind::StaticCast,
TokenKind::KwDynamicCast => CxxCastKind::DynamicCast,
TokenKind::KwReinterpretCast => CxxCastKind::ReinterpretCast,
TokenKind::KwConstCast => CxxCastKind::ConstCast,
_ => CxxCastKind::StaticCast,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeclSpecifier {
Typedef,
Extern,
Static,
Auto,
Register,
Mutable,
ThreadLocal,
Constexpr,
Const,
Volatile,
Restrict,
Inline,
Virtual,
Explicit,
Type(String),
Struct(String),
Union(String),
Enum(String),
Class(String),
Namespace(String),
Using,
TypeAlias,
Template,
Friend,
Typename,
}
#[derive(Debug, Clone)]
pub struct Declarator {
pub name: String,
pub params: Option<Vec<ParamDecl>>,
pub ptr_depth: usize,
pub array_size: Option<Expr>,
pub initializer: Option<Box<Expr>>,
pub asm_label: Option<String>,
pub member_init: Option<Vec<MemberInit>>,
}
#[derive(Debug, Clone)]
pub struct MemberInit {
pub member: String,
pub expr: Expr,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccessSpecifier {
Public,
Protected,
Private,
}
impl Default for AccessSpecifier {
fn default() -> Self {
Self::Public
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CxxCastKind {
StaticCast,
DynamicCast,
ReinterpretCast,
ConstCast,
}
#[derive(Debug, Clone)]
pub struct TemplateParam {
pub name: String,
pub kind: TemplateParamKind,
pub default_value: Option<Expr>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TemplateParamKind {
Type,
NonType,
Template,
}
#[derive(Debug, Clone)]
pub struct ModuleDeclaration {
pub name: String,
pub is_exported: bool,
pub is_partition: bool,
pub partition_name: Option<String>,
pub declarations: Vec<Declaration>,
}
#[derive(Debug, Clone)]
pub enum Stmt {
Empty,
Compound(Vec<Stmt>),
Declaration(Box<Declaration>),
Expr(Option<Box<Expr>>),
If {
cond: Option<Box<Expr>>,
then_branch: Box<Stmt>,
else_branch: Option<Box<Stmt>>,
},
Switch {
expr: Option<Box<Expr>>,
body: Box<Stmt>,
},
While {
cond: Option<Box<Expr>>,
body: Box<Stmt>,
},
DoWhile {
body: Box<Stmt>,
cond: Option<Box<Expr>>,
},
For {
init: Option<Box<Stmt>>,
cond: Option<Box<Expr>>,
incr: Option<Box<Expr>>,
body: Box<Stmt>,
},
Return(Option<Box<Expr>>),
Break,
Continue,
Goto(String),
Case {
expr: Box<Expr>,
end: Option<Box<Expr>>,
stmt: Box<Stmt>,
},
Default(Box<Stmt>),
Labeled {
label: String,
stmt: Box<Stmt>,
},
Try {
body: Box<Stmt>,
handlers: Vec<Stmt>,
},
CoReturn(Option<Box<Expr>>),
CoYield(Box<Expr>),
Coroutine(CoroutineStmt),
}
#[derive(Debug, Clone)]
pub struct CoroutineStmt {
pub kind: CoroutineStmtKind,
pub expr: Option<Box<Expr>>,
pub await_expr: Option<Box<Expr>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoroutineStmtKind {
CoAwait,
CoYield,
CoReturn,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
Void,
Int,
Char,
Short,
Long,
LongLong,
Float,
Double,
LongDouble,
Bool,
Complex,
Imaginary,
Pointer(Box<Type>),
Array(Box<Type>, Option<usize>),
Function(Box<Type>, Vec<Type>),
Named(String),
StructType(String),
UnionType(String),
EnumType(String),
ClassType(String),
Const(Box<Type>),
Volatile(Box<Type>),
Restrict(Box<Type>),
}
impl Type {
pub fn from_specifiers(specs: &[DeclSpecifier]) -> Self {
for spec in specs {
match spec {
DeclSpecifier::Type(t) => match t.as_str() {
"void" => return Type::Void,
"int" => return Type::Int,
"char" => return Type::Char,
"short" => return Type::Short,
"long" => return Type::Long,
"float" => return Type::Float,
"double" => return Type::Double,
"_Bool" => return Type::Bool,
"_Complex" => return Type::Complex,
_ => return Type::Named(t.clone()),
},
DeclSpecifier::Struct(name) => return Type::StructType(name.clone()),
DeclSpecifier::Union(name) => return Type::UnionType(name.clone()),
DeclSpecifier::Enum(name) => return Type::EnumType(name.clone()),
DeclSpecifier::Class(name) => return Type::ClassType(name.clone()),
_ => {}
}
}
Type::Int
}
}
#[derive(Debug, Clone)]
pub enum Expr {
Ident(String),
Literal(Literal),
NullPtr,
This,
Binary {
op: BinaryOp,
left: Box<Expr>,
right: Box<Expr>,
},
Unary {
op: UnaryOp,
expr: Box<Expr>,
},
Conditional {
cond: Box<Expr>,
then_expr: Box<Expr>,
else_expr: Box<Expr>,
},
Call {
callee: Box<Expr>,
args: Vec<Expr>,
},
Subscript {
array: Box<Expr>,
index: Box<Expr>,
},
Member {
object: Box<Expr>,
member: String,
},
Arrow {
object: Box<Expr>,
member: String,
},
PtrToMember {
object: Box<Expr>,
member: Box<Expr>,
},
Cast {
target_type: Type,
expr: Box<Expr>,
},
CxxCast {
kind: CxxCastKind,
expr: Box<Expr>,
target_type: Type,
},
SizeOf(Box<Expr>),
AlignOf(Type),
TypeName(Type),
Throw(Option<Box<Expr>>),
New {
new_type: Type,
args: Vec<Expr>,
init: Option<Box<Expr>>,
},
Delete {
expr: Box<Expr>,
is_array: bool,
},
CoAwait(Box<Expr>),
Lambda(Box<LambdaExpr>),
Requires(Box<RequiresExpr>),
StmtExpr(Box<Stmt>),
BuiltinCall {
name: String,
args: Vec<Expr>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Comma,
Assign,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
ModAssign,
ShlAssign,
ShrAssign,
AndAssign,
OrAssign,
XorAssign,
LogicalOr,
LogicalAnd,
BitOr,
BitXor,
BitAnd,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
Spaceship,
Shl,
Shr,
Add,
Sub,
Mul,
Div,
Mod,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
PreInc,
PreDec,
PostInc,
PostDec,
Plus,
Minus,
Not,
BitNot,
Deref,
AddrOf,
}
#[derive(Debug, Clone)]
pub enum Literal {
Int(i64),
Float(f64),
Char(char),
String(String),
Bool(bool),
}
#[derive(Debug, Clone)]
pub struct LambdaExpr {
pub capture: CaptureClause,
pub params: Vec<ParamDecl>,
pub is_mutable: bool,
pub return_type: Option<Type>,
pub body: Stmt,
}
#[derive(Debug, Clone, Default)]
pub struct CaptureClause {
pub captures: Vec<Capture>,
pub is_default_ref: bool,
pub is_default_copy: bool,
}
#[derive(Debug, Clone)]
pub struct Capture {
pub name: String,
pub by_ref: bool,
pub is_this: bool,
}
#[derive(Debug, Clone)]
pub struct RequiresExpr {
pub params: Vec<ParamDecl>,
pub requirements: Vec<Requirement>,
}
#[derive(Debug, Clone)]
pub enum Requirement {
Simple(Expr),
Type(Type),
Compound { expr: Expr, return_type: Type },
Nested(RequiresExpr),
}
#[derive(Debug, Clone, Default)]
pub struct TranslationUnit {
pub declarations: Vec<Declaration>,
}
#[derive(Debug, Clone)]
pub enum Declaration {
Empty,
Variable(VarDecl),
Function(FunctionDecl),
Struct(StructDecl),
Union(UnionDecl),
Enum(EnumDecl),
Class(ClassDecl),
Namespace(NamespaceDecl),
Template(TemplateDecl),
Typedef(TypedefDecl),
TypeAlias(TypeAliasDecl),
Using(UsingDecl),
StaticAssert(StaticAssertDecl),
Statement(Box<Stmt>),
DeclList(Vec<Declaration>),
}
#[derive(Debug, Clone)]
pub struct VarDecl {
pub name: String,
pub var_type: Type,
pub initializer: Option<Box<Expr>>,
pub specifiers: Vec<DeclSpecifier>,
}
#[derive(Debug, Clone)]
pub struct FunctionDecl {
pub name: String,
pub return_type: Type,
pub params: Vec<ParamDecl>,
pub body: Option<Box<Stmt>>,
pub is_definition: bool,
pub specifiers: Vec<DeclSpecifier>,
pub attributes: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ParamDecl {
pub name: String,
pub param_type: Type,
pub default_value: Option<Expr>,
}
#[derive(Debug, Clone)]
pub struct StructDecl {
pub name: String,
pub fields: Vec<FieldDecl>,
}
#[derive(Debug, Clone)]
pub struct UnionDecl {
pub name: String,
pub fields: Vec<FieldDecl>,
}
#[derive(Debug, Clone)]
pub struct EnumDecl {
pub name: String,
pub enumerators: Vec<EnumeratorDecl>,
}
#[derive(Debug, Clone)]
pub struct FieldDecl {
pub name: String,
pub field_type: Type,
pub bit_width: Option<Expr>,
}
#[derive(Debug, Clone)]
pub struct EnumeratorDecl {
pub name: String,
pub value: Option<Expr>,
}
#[derive(Debug, Clone)]
pub struct ClassDecl {
pub name: String,
pub bases: Vec<BaseClassDecl>,
pub members: Vec<Declaration>,
pub is_struct: bool,
}
#[derive(Debug, Clone)]
pub struct BaseClassDecl {
pub name: String,
pub access: AccessSpecifier,
pub is_virtual: bool,
}
#[derive(Debug, Clone)]
pub struct NamespaceDecl {
pub name: String,
pub declarations: Vec<Declaration>,
}
#[derive(Debug, Clone)]
pub struct TemplateDecl {
pub params: Vec<TemplateParam>,
pub declaration: Box<Declaration>,
}
#[derive(Debug, Clone)]
pub struct TypedefDecl {
pub name: String,
pub aliased_type: Type,
}
#[derive(Debug, Clone)]
pub struct TypeAliasDecl {
pub name: String,
pub aliased_type: Type,
}
#[derive(Debug, Clone)]
pub struct UsingDecl {
pub name: String,
pub target: String,
}
#[derive(Debug, Clone)]
pub struct StaticAssertDecl {
pub expr: Expr,
pub message: Option<String>,
}
impl X86ParserDeep {
fn parse_struct_or_class(&mut self, is_struct: bool) -> Option<DeclSpecifier> {
let name = self.parse_identifier().unwrap_or_default();
if self.gnu_mode && self.peek_kind() == Some(&TokenKind::KwAttribute) {
self.advance();
self.parse_gnu_attribute();
}
let _bases = if self.cpp_mode && self.match_token(TokenKind::Colon) {
self.parse_base_clause()
} else {
vec![]
};
if name.is_empty() && self.peek_kind() != Some(&TokenKind::LBrace) {
return Some(if is_struct {
DeclSpecifier::Struct(String::new())
} else {
DeclSpecifier::Class(String::new())
});
}
if self.match_token(TokenKind::LBrace) {
let _members = self.parse_class_members();
self.expect(TokenKind::RBrace).ok();
if !name.is_empty() {
self.tag_names.insert(name.clone());
}
}
if is_struct {
Some(DeclSpecifier::Struct(name))
} else {
Some(DeclSpecifier::Class(name))
}
}
fn parse_base_clause(&mut self) -> Vec<BaseClassDecl> {
let mut bases = Vec::new();
loop {
let access = match self.peek_kind() {
Some(TokenKind::KwPublic) => {
self.advance();
AccessSpecifier::Public
}
Some(TokenKind::KwProtected) => {
self.advance();
AccessSpecifier::Protected
}
Some(TokenKind::KwPrivate) => {
self.advance();
AccessSpecifier::Private
}
_ => AccessSpecifier::Private, };
let is_virtual = self.match_identifier("virtual");
let name = self.parse_identifier().unwrap_or_default();
bases.push(BaseClassDecl {
name,
access,
is_virtual,
});
if !self.match_token(TokenKind::Comma) {
break;
}
}
bases
}
fn parse_class_members(&mut self) -> Vec<Declaration> {
let mut members = Vec::new();
self.in_class_body = true;
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
match self.peek_kind() {
Some(TokenKind::KwPublic) => {
self.advance();
self.match_token(TokenKind::Colon);
self.current_access = AccessSpecifier::Public;
continue;
}
Some(TokenKind::KwProtected) => {
self.advance();
self.match_token(TokenKind::Colon);
self.current_access = AccessSpecifier::Protected;
continue;
}
Some(TokenKind::KwPrivate) => {
self.advance();
self.match_token(TokenKind::Colon);
self.current_access = AccessSpecifier::Private;
continue;
}
_ => {}
}
if let Some(decl) = self.parse_external_declaration() {
members.push(decl);
} else {
self.skip_to_recovery_point();
if self.peek_kind() == Some(&TokenKind::RBrace) {
break;
}
}
}
self.in_class_body = false;
self.current_access = AccessSpecifier::Public;
members
}
fn parse_union(&mut self) -> Option<DeclSpecifier> {
let name = self.parse_identifier().unwrap_or_default();
if self.match_token(TokenKind::LBrace) {
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
if let Some(_decl) = self.parse_declaration_or_function() {
} else {
self.skip_to(TokenKind::Semicolon);
self.advance();
}
}
self.expect(TokenKind::RBrace).ok();
if !name.is_empty() {
self.tag_names.insert(name.clone());
}
}
Some(DeclSpecifier::Union(name))
}
fn parse_enum(&mut self) -> Option<DeclSpecifier> {
let _is_scoped =
self.cpp_mode && (self.match_identifier("class") || self.match_identifier("struct"));
let name = self.parse_identifier().unwrap_or_default();
if self.cpp_mode && self.match_token(TokenKind::Colon) {
self.parse_type_specifier_for_cast();
}
if self.match_token(TokenKind::LBrace) {
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
let _ename = self.parse_identifier().unwrap_or_default();
if self.match_token(TokenKind::Equal) {
self.parse_conditional_expression();
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
self.expect(TokenKind::RBrace).ok();
if !name.is_empty() {
self.tag_names.insert(name.clone());
}
}
Some(DeclSpecifier::Enum(name))
}
fn parse_namespace(&mut self) -> Option<Declaration> {
self.advance(); let name = self.parse_identifier().unwrap_or_default();
self.namespace_stack.push(name.clone());
let declarations = if self.match_token(TokenKind::LBrace) {
let mut decls = Vec::new();
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
if let Some(decl) = self.parse_external_declaration() {
decls.push(decl);
} else {
break;
}
}
self.expect(TokenKind::RBrace).ok();
decls
} else {
vec![]
};
self.namespace_stack.pop();
Some(Declaration::Namespace(NamespaceDecl { name, declarations }))
}
fn parse_template_declaration(&mut self) -> Option<Declaration> {
self.advance(); self.expect(TokenKind::Less).ok();
let params = self.parse_template_parameter_list();
self.expect(TokenKind::Greater).ok();
if self.cpp_mode && self.peek_kind() == Some(&TokenKind::KwRequires) {
self.parse_requires_clause();
}
let decl = self.parse_external_declaration()?;
Some(Declaration::Template(TemplateDecl {
params,
declaration: Box::new(decl),
}))
}
fn parse_template_parameter_list(&mut self) -> Vec<TemplateParam> {
let mut params = Vec::new();
self.in_template_params = true;
loop {
if self.peek_kind() == Some(&TokenKind::Greater) {
break;
}
let kind = match self.peek_kind() {
Some(TokenKind::KwTypename) | Some(TokenKind::KwClass) => {
self.advance();
TemplateParamKind::Type
}
Some(TokenKind::KwTemplate) => {
self.advance();
TemplateParamKind::Template
}
_ => TemplateParamKind::NonType,
};
let name = if kind == TemplateParamKind::NonType {
self.parse_decl_specifiers();
self.parse_identifier().unwrap_or_default()
} else {
self.parse_identifier().unwrap_or_default()
};
let default_value = if self.match_token(TokenKind::Equal) {
self.parse_conditional_expression()
} else {
None
};
params.push(TemplateParam {
name,
kind,
default_value,
});
if !self.match_token(TokenKind::Comma) {
break;
}
}
self.in_template_params = false;
params
}
fn parse_template_argument_list(&mut self) -> Option<()> {
loop {
if self.is_at_type_specifier() {
self.parse_type_specifier_for_cast();
} else if let Some(_expr) = self.parse_conditional_expression() {
} else {
return None;
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
Some(())
}
fn at_concept_definition(&self) -> bool {
if self.peek().map(|t| t.text == "concept").unwrap_or(false) {
true
} else {
false
}
}
fn parse_concept_definition(&mut self) -> Option<Declaration> {
self.advance(); let name = self.parse_identifier()?;
self.expect(TokenKind::Equal).ok();
let _constraint = self.parse_expression();
self.match_token(TokenKind::Semicolon);
Some(Declaration::Variable(VarDecl {
name,
var_type: Type::Bool,
initializer: None,
specifiers: vec![],
}))
}
fn parse_requires_clause(&mut self) -> Option<Expr> {
self.advance(); self.parse_logical_or_expression()
}
fn parse_requires_expression(&mut self) -> Option<Expr> {
self.advance(); self.requires_expr_depth += 1;
let params = if self.match_token(TokenKind::LParen) {
let p = self.parse_parameter_list();
self.expect(TokenKind::RParen).ok();
p
} else {
vec![]
};
self.expect(TokenKind::LBrace).ok();
let mut requirements = Vec::new();
while !self.is_eof() && self.peek_kind() != Some(&TokenKind::RBrace) {
if let Some(req) = self.parse_requirement() {
requirements.push(req);
} else {
break;
}
}
self.expect(TokenKind::RBrace).ok();
self.requires_expr_depth -= 1;
Some(Expr::Requires(Box::new(RequiresExpr {
params,
requirements,
})))
}
fn parse_requirement(&mut self) -> Option<Requirement> {
match self.peek_kind() {
Some(TokenKind::KwTypename) => {
self.advance();
let _type = Type::from_specifiers(&self.parse_decl_specifiers());
self.match_token(TokenKind::Semicolon);
Some(Requirement::Type(Type::Void))
}
_ => {
let expr = self.parse_expression()?;
self.match_token(TokenKind::Semicolon);
Some(Requirement::Simple(expr))
}
}
}
fn parse_lambda_expression(&mut self) -> Option<Expr> {
self.expect(TokenKind::LBracket).ok();
let capture = self.parse_lambda_capture();
self.expect(TokenKind::RBracket).ok();
if self.cpp_mode && self.match_token(TokenKind::Less) {
self.parse_template_parameter_list();
self.expect(TokenKind::Greater).ok();
}
if self.cpp_mode && self.peek_kind() == Some(&TokenKind::KwRequires) {
self.parse_requires_clause();
}
self.expect(TokenKind::LParen).ok();
let params = if self.peek_kind() != Some(&TokenKind::RParen) {
self.parse_parameter_list()
} else {
vec![]
};
self.expect(TokenKind::RParen).ok();
let is_mutable = self.match_identifier("mutable");
if self.cpp_mode {
self.match_token(TokenKind::KwConstexpr);
}
if self.cpp_mode {
self.match_token(TokenKind::KwNoexcept);
}
let return_type = if self.match_token(TokenKind::Arrow) {
Some(Type::from_specifiers(&self.parse_decl_specifiers()))
} else {
None
};
if self.cpp_mode && self.peek_kind() == Some(&TokenKind::KwRequires) {
self.parse_requires_clause();
}
let body = self.parse_compound_statement();
Some(Expr::Lambda(Box::new(LambdaExpr {
capture,
params,
is_mutable,
return_type,
body,
})))
}
fn parse_lambda_expression_after_capture(&mut self) -> Option<Expr> {
self.parse_lambda_expression()
}
fn parse_lambda_capture(&mut self) -> CaptureClause {
let mut clause = CaptureClause::default();
if self.peek_kind() == Some(&TokenKind::RBracket) {
return clause;
}
if self.match_token(TokenKind::Equal) {
clause.is_default_copy = true;
if self.peek_kind() != Some(&TokenKind::RBracket) {
self.expect(TokenKind::Comma).ok();
}
} else if self.match_token(TokenKind::Ampersand) {
clause.is_default_ref = true;
if self.peek_kind() != Some(&TokenKind::RBracket) {
self.expect(TokenKind::Comma).ok();
}
}
loop {
if self.peek_kind() == Some(&TokenKind::RBracket) {
break;
}
let by_ref = self.match_token(TokenKind::Ampersand);
let is_this = self.match_identifier("this");
let name = self.parse_identifier().unwrap_or_default();
clause.captures.push(Capture {
name,
by_ref,
is_this,
});
if !self.match_token(TokenKind::Comma) {
break;
}
}
clause
}
fn parse_coroutine_body(&mut self) -> Option<Stmt> {
let _stmt = self.parse_compound_statement();
self.in_coroutine = true;
Some(Stmt::Coroutine(CoroutineStmt {
kind: CoroutineStmtKind::CoAwait,
expr: None,
await_expr: None,
}))
}
fn at_module_declaration(&self) -> bool {
self.peek().map(|t| t.text == "module").unwrap_or(false)
}
fn parse_module_declaration(&mut self) -> Option<Declaration> {
self.advance(); let name = self.parse_identifier()?;
self.match_token(TokenKind::Semicolon);
self.module_decl = Some(ModuleDeclaration {
name: name.clone(),
is_exported: false,
is_partition: false,
partition_name: None,
declarations: vec![],
});
Some(Declaration::Variable(VarDecl {
name,
var_type: Type::Void,
initializer: None,
specifiers: vec![],
}))
}
fn parse_export_declaration(&mut self) -> Option<Declaration> {
if self.match_identifier("module") {
let name = self.parse_identifier()?;
self.match_token(TokenKind::Semicolon);
return Some(Declaration::Variable(VarDecl {
name,
var_type: Type::Void,
initializer: None,
specifiers: vec![],
}));
}
self.parse_external_declaration()
}
fn parse_new_expression(&mut self) -> Option<Expr> {
self.advance(); let mut placement_args = Vec::new();
if self.match_token(TokenKind::LParen) {
loop {
if let Some(arg) = self.parse_assignment_expression() {
placement_args.push(arg);
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
self.expect(TokenKind::RParen).ok();
}
let new_type = Type::from_specifiers(&self.parse_decl_specifiers());
let init = if self.match_token(TokenKind::LParen) {
let init_expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
init_expr.map(Box::new)
} else {
None
};
Some(Expr::New {
new_type,
args: placement_args,
init,
})
}
fn parse_delete_expression(&mut self) -> Option<Expr> {
self.advance(); let is_array = self.match_token(TokenKind::LBracket) && {
self.expect(TokenKind::RBracket).ok();
true
};
let expr = self.parse_cast_expression()?;
Some(Expr::Delete {
expr: Box::new(expr),
is_array,
})
}
fn parse_using_declaration(&mut self) -> Option<Declaration> {
self.advance(); let _is_namespace = self.match_identifier("namespace");
let name = self.parse_identifier()?;
if self.match_token(TokenKind::Equal) {
let aliased_type = Type::from_specifiers(&self.parse_decl_specifiers());
self.match_token(TokenKind::Semicolon);
Some(Declaration::TypeAlias(TypeAliasDecl { name, aliased_type }))
} else {
self.match_token(TokenKind::Semicolon);
Some(Declaration::Using(UsingDecl {
name,
target: String::new(),
}))
}
}
}
impl X86ParserDeep {
fn parse_gnu_attribute(&mut self) -> Option<Vec<String>> {
let mut attrs = Vec::new();
if self.match_token(TokenKind::LParen) {
if self.match_token(TokenKind::LParen) {
loop {
if let Some(name) = self.parse_identifier() {
attrs.push(name);
if self.match_token(TokenKind::LParen) {
self.parse_expression();
self.expect(TokenKind::RParen).ok();
}
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
self.expect(TokenKind::RParen).ok();
}
self.expect(TokenKind::RParen).ok();
}
Some(attrs)
}
fn parse_stmt_expr(&mut self) -> Option<Expr> {
self.expect(TokenKind::LParen).ok();
let stmt = self.parse_compound_statement();
let _expr = self.parse_expression();
self.expect(TokenKind::RParen).ok();
Some(Expr::StmtExpr(Box::new(stmt)))
}
fn parse_builtin_va_arg(&mut self) -> Option<Expr> {
self.advance(); self.expect(TokenKind::LParen).ok();
let ap = self.parse_assignment_expression();
self.expect(TokenKind::Comma).ok();
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::RParen).ok();
ap.map(|e| Expr::BuiltinCall {
name: "__builtin_va_arg".into(),
args: vec![e],
})
}
fn parse_builtin_offsetof(&mut self) -> Option<Expr> {
self.advance();
self.expect(TokenKind::LParen).ok();
let _type = self.parse_type_specifier_for_cast();
self.expect(TokenKind::Comma).ok();
let member = self.parse_identifier()?;
self.expect(TokenKind::RParen).ok();
Some(Expr::BuiltinCall {
name: "__builtin_offsetof".into(),
args: vec![Expr::Ident(member)],
})
}
fn parse_builtin_choose_expr(&mut self) -> Option<Expr> {
self.advance();
self.expect(TokenKind::LParen).ok();
let cond = self.parse_assignment_expression()?;
self.expect(TokenKind::Comma).ok();
let expr1 = self.parse_assignment_expression()?;
self.expect(TokenKind::Comma).ok();
let expr2 = self.parse_assignment_expression()?;
self.expect(TokenKind::RParen).ok();
Some(Expr::BuiltinCall {
name: "__builtin_choose_expr".into(),
args: vec![cond, expr1, expr2],
})
}
fn parse_builtin_types_compatible(&mut self) -> Option<Expr> {
self.advance();
self.expect(TokenKind::LParen).ok();
let _t1 = self.parse_type_specifier_for_cast();
self.expect(TokenKind::Comma).ok();
let _t2 = self.parse_type_specifier_for_cast();
self.expect(TokenKind::RParen).ok();
Some(Expr::Literal(Literal::Bool(true)))
}
fn parse_typeof_expression(&mut self) -> Option<Expr> {
self.advance(); self.expect(TokenKind::LParen).ok();
let expr = if self.is_at_type_specifier() {
let ty = Type::from_specifiers(&self.parse_decl_specifiers());
Expr::TypeName(ty)
} else {
self.parse_expression()?
};
self.expect(TokenKind::RParen).ok();
Some(Expr::Unary {
op: UnaryOp::Plus,
expr: Box::new(expr),
}) }
fn parse_case_range_expression(&mut self) -> Option<Expr> {
let low = self.parse_conditional_expression()?;
self.expect(TokenKind::Ellipsis).ok();
let high = self.parse_conditional_expression()?;
Some(Expr::Binary {
op: BinaryOp::Comma,
left: Box::new(low),
right: Box::new(high),
})
}
fn parse_label_declaration(&mut self) -> Option<Declaration> {
self.advance(); let mut labels = Vec::new();
loop {
if let Some(name) = self.parse_identifier() {
labels.push(name);
}
if !self.match_token(TokenKind::Comma) {
break;
}
}
self.match_token(TokenKind::Semicolon);
Some(Declaration::Variable(VarDecl {
name: labels.join(","),
var_type: Type::Void,
initializer: None,
specifiers: vec![],
}))
}
fn skip_ms_declspec(&mut self) {
if self.peek().map(|t| t.text == "__declspec").unwrap_or(false) {
self.advance();
if self.match_token(TokenKind::LParen) {
self.parse_expression();
self.match_token(TokenKind::RParen);
}
}
}
fn match_identifier(&mut self, name: &str) -> bool {
if self
.peek()
.map(|t| t.text == name && t.kind == TokenKind::Identifier)
.unwrap_or(false)
{
self.advance();
true
} else {
false
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MSCallingConvention {
Cdecl,
Stdcall,
Fastcall,
Thiscall,
Vectorcall,
Clrcall,
}
impl MSCallingConvention {
pub fn from_str(s: &str) -> Option<Self> {
match s {
"__cdecl" => Some(Self::Cdecl),
"__stdcall" => Some(Self::Stdcall),
"__fastcall" => Some(Self::Fastcall),
"__thiscall" => Some(Self::Thiscall),
"__vectorcall" => Some(Self::Vectorcall),
"__clrcall" => Some(Self::Clrcall),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MSTypeAttribute {
Ptr32,
Ptr64,
Unaligned,
Based(String),
Restrict,
Noalias,
}
impl MSTypeAttribute {
pub fn from_str(s: &str) -> Option<Self> {
match s {
"__ptr32" => Some(Self::Ptr32),
"__ptr64" => Some(Self::Ptr64),
"__unaligned" => Some(Self::Unaligned),
"__restrict" => Some(Self::Restrict),
"__noalias" => Some(Self::Noalias),
_ if s.starts_with("__based") => Some(Self::Based(s.to_string())),
_ => None,
}
}
}
impl X86ParserDeep {
pub fn parse_ms_declspec(&mut self) -> Option<String> {
self.expect(TokenKind::LParen).ok();
let name = self.parse_identifier()?;
if self.match_token(TokenKind::LParen) {
self.parse_expression();
self.match_token(TokenKind::RParen);
}
self.match_token(TokenKind::RParen);
Some(name)
}
pub fn parse_ms_calling_convention(&mut self) -> Option<MSCallingConvention> {
match self.peek().map(|t| t.text.as_str()) {
Some("__cdecl") | Some("__stdcall") | Some("__fastcall") | Some("__thiscall")
| Some("__vectorcall") => {
let text = self.advance().unwrap().text;
MSCallingConvention::from_str(&text)
}
_ => None,
}
}
pub fn parse_ms_type_modifier(&mut self) -> Option<MSTypeAttribute> {
match self.peek().map(|t| t.text.as_str()) {
Some("__ptr32") | Some("__ptr64") | Some("__unaligned") | Some("__restrict")
| Some("__noalias") => {
let text = self.advance().unwrap().text;
MSTypeAttribute::from_str(&text)
}
Some(s) if s.starts_with("__based") => {
let text = self.advance().unwrap().text;
MSTypeAttribute::from_str(&text)
}
_ => None,
}
}
pub fn parse_ms_seh_try(&mut self) -> Option<Stmt> {
self.advance();
let body = self.parse_compound_statement();
match self.peek().map(|t| t.text.as_str()) {
Some("__except") => {
self.advance();
self.expect(TokenKind::LParen).ok();
let _filter = self.parse_expression();
self.expect(TokenKind::RParen).ok();
let handler = self.parse_compound_statement();
Some(Stmt::Compound(vec![body, handler]))
}
Some("__finally") => {
self.advance();
let finally_body = self.parse_compound_statement();
Some(Stmt::Compound(vec![body, finally_body]))
}
_ => Some(body),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::clang::lexer::Lexer;
fn tokenize(source: &str) -> Vec<Token> {
let mut lex = Lexer::new(source, CLangStandard::C17);
lex.lex_all();
lex.tokens
}
fn tokenize_cpp(source: &str) -> Vec<Token> {
let mut lex = Lexer::new(source, CLangStandard::C17);
lex.lex_all();
lex.tokens
}
#[test]
fn test_parse_simple_expression() {
let tokens = tokenize("1 + 2");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_binary_expression() {
let tokens = tokenize("a + b * c");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_function_call() {
let tokens = tokenize("foo(1, 2, 3)");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_member_access() {
let tokens = tokenize("obj.field");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_array_subscript() {
let tokens = tokenize("arr[i]");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_comparison() {
let tokens = tokenize("a == b");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_logical_and() {
let tokens = tokenize("a && b");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_ternary() {
let tokens = tokenize("a ? b : c");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_assignment() {
let tokens = tokenize("x = 5");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_unary() {
let tokens = tokenize("!flag");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_sizeof() {
let tokens = tokenize("sizeof(int)");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_return_statement() {
let tokens = tokenize("return 42;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let stmt = parser.parse_statement();
assert!(stmt.is_some());
}
#[test]
fn test_parse_if_statement() {
let tokens = tokenize("if (x) return 1; else return 0;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let stmt = parser.parse_statement();
assert!(stmt.is_some());
}
#[test]
fn test_parse_while_statement() {
let tokens = tokenize("while (1) { break; }");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let stmt = parser.parse_statement();
assert!(stmt.is_some());
}
#[test]
fn test_parse_for_statement() {
let tokens = tokenize("for (int i = 0; i < 10; i++) { }");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let stmt = parser.parse_statement();
assert!(stmt.is_some());
}
#[test]
fn test_parse_compound_statement() {
let tokens = tokenize("{ int x = 1; return x; }");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let stmt = parser.parse_statement();
assert!(stmt.is_some());
}
#[test]
fn test_parse_variable_declaration() {
let tokens = tokenize("int x;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(parser.errors.is_empty());
}
#[test]
fn test_parse_function_definition() {
let tokens = tokenize("int main() { return 0; }");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(parser.errors.is_empty());
}
#[test]
fn test_parse_struct_definition() {
let tokens = tokenize("struct Point { int x; int y; };");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(parser.errors.is_empty());
}
#[test]
fn test_parse_enum_definition() {
let tokens = tokenize("enum Color { RED, GREEN, BLUE };");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(parser.errors.is_empty());
}
#[test]
fn test_parse_typedef() {
let tokens = tokenize("typedef int myint;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_class() {
let tokens = tokenize_cpp("class Foo { public: int x; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_class_with_inheritance() {
let tokens = tokenize_cpp("class Derived : public Base { };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_namespace() {
let tokens = tokenize_cpp("namespace ns { int x; }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_template_function() {
let tokens = tokenize_cpp("template<typename T> T max(T a, T b) { return a > b ? a : b; }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_lambda() {
let tokens = tokenize_cpp("auto f = [](int x) { return x + 1; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_new_delete() {
let tokens = tokenize_cpp("int* p = new int(42); delete p;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_noexcept() {
let tokens = tokenize_cpp("void f() noexcept;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_constexpr() {
let tokens = tokenize_cpp("constexpr int x = 5;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_requires_clause() {
let tokens = tokenize_cpp("template<typename T> requires true void f(T);");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_attribute() {
let tokens = tokenize("void f() __attribute__((noreturn));");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_builtin_va_arg() {
let tokens = tokenize("int x = __builtin_va_arg(ap, int);");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_declspec() {
let tokens = tokenize("__declspec(dllexport) int f();");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_calling_convention() {
let tokens = tokenize("void __stdcall f();");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_with_errors() {
let tokens = tokenize("int x = ;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(!parser.errors.is_empty());
}
#[test]
fn test_parse_recovery_after_error() {
let tokens = tokenize("int x = ; int y = 5;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_precedence_mul_before_add() {
let tokens = tokenize("1 + 2 * 3");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression().unwrap();
assert!(matches!(
expr,
Expr::Binary {
op: BinaryOp::Add,
..
}
));
}
#[test]
fn test_precedence_comma_lowest() {
let tokens = tokenize("a = 1, b = 2");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression().unwrap();
assert!(matches!(
expr,
Expr::Binary {
op: BinaryOp::Comma,
..
}
));
}
#[test]
fn test_decl_specifier_type_display() {
let spec = DeclSpecifier::Type("int".into());
assert_eq!(format!("{:?}", spec), "Type(\"int\")");
}
#[test]
fn test_type_from_specifiers() {
let specs = vec![DeclSpecifier::Type("int".into())];
assert_eq!(Type::from_specifiers(&specs), Type::Int);
}
#[test]
fn test_binary_op_variants() {
let ops = [
BinaryOp::Add,
BinaryOp::Sub,
BinaryOp::Mul,
BinaryOp::Div,
BinaryOp::Eq,
BinaryOp::Ne,
BinaryOp::Lt,
BinaryOp::Gt,
BinaryOp::LogicalAnd,
BinaryOp::LogicalOr,
BinaryOp::Assign,
];
assert_eq!(ops.len(), 11);
}
#[test]
fn test_cxx_cast_kind_from_token() {
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwStaticCast),
CxxCastKind::StaticCast
);
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwDynamicCast),
CxxCastKind::DynamicCast
);
}
#[test]
fn test_ms_calling_convention_from_str() {
assert_eq!(
MSCallingConvention::from_str("__stdcall"),
Some(MSCallingConvention::Stdcall)
);
assert_eq!(
MSCallingConvention::from_str("__fastcall"),
Some(MSCallingConvention::Fastcall)
);
assert_eq!(
MSCallingConvention::from_str("__cdecl"),
Some(MSCallingConvention::Cdecl)
);
assert_eq!(MSCallingConvention::from_str("nonexistent"), None);
}
#[test]
fn test_ms_type_attribute_from_str() {
assert_eq!(
MSTypeAttribute::from_str("__ptr32"),
Some(MSTypeAttribute::Ptr32)
);
assert_eq!(
MSTypeAttribute::from_str("__ptr64"),
Some(MSTypeAttribute::Ptr64)
);
assert_eq!(
MSTypeAttribute::from_str("__unaligned"),
Some(MSTypeAttribute::Unaligned)
);
assert_eq!(MSTypeAttribute::from_str("unknown"), None);
}
#[test]
fn test_parse_full_translation_unit() {
let source = r#"
int global_var = 42;
static void helper(int x) {
return;
}
int main(void) {
int local = 1;
if (local) {
return 0;
}
return 1;
}
"#;
let tokens = tokenize(source);
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parser_gnu_mode() {
let mut p = X86ParserDeep::new_gnu(vec![], CLangStandard::C17);
assert!(p.gnu_mode);
assert!(!p.cpp_mode);
}
#[test]
fn test_parser_ms_mode() {
let mut p = X86ParserDeep::new_ms(vec![], CLangStandard::C17);
assert!(p.ms_mode);
}
#[test]
fn test_parser_cpp_mode() {
let mut p = X86ParserDeep::new_cpp(vec![], CLangStandard::C17);
assert!(p.cpp_mode);
}
#[test]
fn test_save_restore_state() {
let mut p = X86ParserDeep::new(vec![], CLangStandard::C17);
p.errors.push(ParseError::new("test", SourceLoc::default()));
let state = p.save_state();
p.errors
.push(ParseError::new("another", SourceLoc::default()));
p.restore_state(state);
assert_eq!(p.errors.len(), 1);
}
#[test]
fn test_access_specifier_default() {
assert_eq!(AccessSpecifier::default(), AccessSpecifier::Public);
}
#[test]
fn test_member_init_construction() {
let init = MemberInit {
member: "x".into(),
expr: Expr::Literal(Literal::Int(5)),
};
assert_eq!(init.member, "x");
}
#[test]
fn test_declarator_default() {
let d = Declarator {
name: "foo".into(),
params: None,
ptr_depth: 0,
array_size: None,
initializer: None,
asm_label: None,
member_init: None,
};
assert_eq!(d.name, "foo");
assert_eq!(d.ptr_depth, 0);
}
#[test]
fn test_parse_cpp_range_for() {
let tokens = tokenize_cpp("for (auto x : vec) { }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_access_specifiers() {
let tokens = tokenize_cpp("class A { public: int x; protected: int y; private: int z; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_virtual_inheritance() {
let tokens = tokenize_cpp("class D : public virtual B { };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_pure_virtual() {
let tokens = tokenize_cpp("class Abstract { virtual void f() = 0; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_using_directive() {
let tokens = tokenize_cpp("using namespace std;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_type_alias() {
let tokens = tokenize_cpp("using MyInt = int;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_static_assert() {
let tokens = tokenize_cpp("static_assert(sizeof(int) == 4, \"int size check\");");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_enum_class() {
let tokens = tokenize_cpp("enum class Color { Red, Green, Blue };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_constructor_initializer() {
let tokens = tokenize_cpp("struct S { int x; S() : x(0) { } };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_default_delete() {
let tokens = tokenize_cpp("struct S { S() = default; ~S() = delete; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_friend() {
let tokens = tokenize_cpp("class A { friend class B; friend void f(); };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_attributes() {
let tokens = tokenize("void f() __attribute__((noreturn, format(printf, 1, 2)));");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_statement_expr() {
let tokens = tokenize("int x = ({ int y = 5; y * y; });");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_case_range() {
let tokens = tokenize("switch(x) { case 1 ... 5: break; }");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_label_decl() {
let tokens = tokenize("__label__ cleanup;");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_typeof() {
let tokens = tokenize("typeof(x) y;");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_gnu_alignof() {
let tokens = tokenize("int s = __alignof__(int);");
let mut parser = X86ParserDeep::new_gnu(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_declspec_multiple() {
let tokens = tokenize("__declspec(dllexport) __declspec(noinline) void f();");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_fastcall() {
let tokens = tokenize("void __fastcall f(int a, int b);");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_vectorcall() {
let tokens = tokenize("void __vectorcall f(float a, float b);");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_thiscall() {
let tokens = tokenize("void __thiscall f();");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_ptr32() {
let tokens = tokenize("__ptr32 int* p;");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_ms_unaligned() {
let tokens = tokenize("__unaligned int* p;");
let mut parser = X86ParserDeep::new_ms(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_try_catch() {
let tokens = tokenize_cpp("try { f(); } catch (const std::exception& e) { }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_throw() {
let tokens = tokenize_cpp("throw std::runtime_error(\"error\");");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_member_init_list() {
let tokens = tokenize_cpp("struct S { int a, b; S(int x, int y) : a(x), b(y) { } };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_operator_overload() {
let tokens = tokenize_cpp("struct Vec { Vec operator+(const Vec& other) const; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_consteval() {
let tokens = tokenize_cpp("consteval int f() { return 42; }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_expression_spaceship() {
let tokens = tokenize_cpp("auto r = a <=> b;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_expression_arrow_star() {
let tokens = tokenize_cpp("int x = obj.*ptr;");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_lambda_generic() {
let tokens = tokenize_cpp("auto f = []<typename T>(T a, T b) { return a + b; };");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_constexpr_if() {
let tokens = tokenize_cpp("if constexpr (sizeof(int) == 4) { }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_expression_precedence_chain() {
let tokens = tokenize("a = b + c * d - e / f % g");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_parse_empty_file() {
let tokens: Vec<Token> = vec![];
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let tu = parser.parse();
assert!(tu.declarations.is_empty());
}
#[test]
fn test_parse_multiple_top_level_decls() {
let tokens = tokenize("int a; int b; int c;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let tu = parser.parse();
assert!(tu.declarations.len() >= 3);
}
#[test]
fn test_parse_function_with_pointers() {
let tokens = tokenize("void f(int* p, char** pp);");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_function_with_arrays() {
let tokens = tokenize("void f(int arr[10]);");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_struct_with_bitfields() {
let tokens = tokenize("struct Flags { unsigned int a:1; unsigned int b:3; };");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_nested_struct() {
let tokens = tokenize("struct Outer { struct Inner { int x; } inner; };");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_variadic_template() {
let tokens = tokenize_cpp("template<typename... Ts> void f(Ts... args);");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_inline_namespace() {
let tokens = tokenize_cpp("inline namespace v1 { int x; }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_cpp_anonymous_namespace() {
let tokens = tokenize_cpp("namespace { int x; }");
let mut parser = X86ParserDeep::new_cpp(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_translation_unit_function_then_var() {
let tokens = tokenize("void f() { } int g;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let tu = parser.parse();
assert!(tu.declarations.len() >= 2);
}
#[test]
fn test_parse_error_recovery_missing_semicolon() {
let tokens = tokenize("int x int y;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
assert!(!parser.errors.is_empty());
}
#[test]
fn test_parse_unary_address_of_deref() {
let tokens = tokenize("int* p = &*ptr;");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
parser.parse();
}
#[test]
fn test_parse_precedence_logical_vs_bitwise() {
let tokens = tokenize("a && b || c");
let mut parser = X86ParserDeep::new(tokens, CLangStandard::C17);
let expr = parser.parse_expression();
assert!(expr.is_some());
}
#[test]
fn test_ms_calling_convention_all() {
for cc in &[
"__cdecl",
"__stdcall",
"__fastcall",
"__thiscall",
"__vectorcall",
] {
let conv = MSCallingConvention::from_str(cc);
assert!(conv.is_some(), "Failed for {}", cc);
}
}
#[test]
fn test_ms_type_attribute_all() {
for attr in &["__ptr32", "__ptr64", "__unaligned"] {
let parsed = MSTypeAttribute::from_str(attr);
assert!(parsed.is_some(), "Failed for {}", attr);
}
}
#[test]
fn test_cxx_cast_kind_all_variants() {
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwStaticCast),
CxxCastKind::StaticCast
);
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwDynamicCast),
CxxCastKind::DynamicCast
);
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwReinterpretCast),
CxxCastKind::ReinterpretCast
);
assert_eq!(
cxx_cast_kind_from_token(TokenKind::KwConstCast),
CxxCastKind::ConstCast
);
}
#[test]
fn test_binary_op_all_variants() {
use std::collections::HashSet;
let mut seen = HashSet::new();
let ops = [
BinaryOp::Add,
BinaryOp::Sub,
BinaryOp::Mul,
BinaryOp::Div,
BinaryOp::Mod,
BinaryOp::Shl,
BinaryOp::Shr,
BinaryOp::Lt,
BinaryOp::Gt,
BinaryOp::Le,
BinaryOp::Ge,
BinaryOp::Eq,
BinaryOp::Ne,
BinaryOp::BitAnd,
BinaryOp::BitXor,
BinaryOp::BitOr,
BinaryOp::LogicalAnd,
BinaryOp::LogicalOr,
BinaryOp::Assign,
BinaryOp::Comma,
];
for op in &ops {
seen.insert(format!("{:?}", op));
}
assert_eq!(seen.len(), ops.len());
}
#[test]
fn test_unary_op_all_variants() {
let ops = [
UnaryOp::PreInc,
UnaryOp::PreDec,
UnaryOp::PostInc,
UnaryOp::PostDec,
UnaryOp::Plus,
UnaryOp::Minus,
UnaryOp::Not,
UnaryOp::BitNot,
UnaryOp::Deref,
UnaryOp::AddrOf,
];
assert_eq!(ops.len(), 10);
}
#[test]
fn test_type_from_specifiers_with_qualifiers() {
let specs = vec![DeclSpecifier::Const, DeclSpecifier::Type("char".into())];
let ty = Type::from_specifiers(&specs);
assert_eq!(ty, Type::Char);
}
}