use std::fmt::{self, Debug, Display};
use c2rust_ast_exporter::clang_ast::LRValue;
use indexmap::{IndexMap, IndexSet};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::ops::Index;
use std::path::PathBuf;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Copy, Clone)]
pub struct CTypeId(pub u64);
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Copy, Clone)]
pub struct CExprId(pub u64);
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Copy, Clone)]
pub struct CDeclId(pub u64);
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Copy, Clone)]
pub struct CStmtId(pub u64);
pub type CLabelId = CStmtId;
pub type CFieldId = CDeclId;
pub type CParamId = CDeclId;
pub type CFuncTypeId = CTypeId;
pub type CRecordId = CDeclId;
pub type CTypedefId = CDeclId;
pub type CEnumId = CDeclId;
pub type CEnumConstantId = CDeclId;
pub use self::conversion::*;
pub use self::print::Printer;
use super::diagnostics::Diagnostic;
mod conversion;
pub mod iterators;
mod print;
#[derive(Debug, Clone)]
pub struct TypedAstContext {
pub c_types: HashMap<CTypeId, CType>,
pub c_exprs: HashMap<CExprId, CExpr>,
pub c_stmts: HashMap<CStmtId, CStmt>,
pub c_decls: IndexMap<CDeclId, CDecl>,
pub c_decls_top: Vec<CDeclId>,
pub c_main: Option<CDeclId>,
pub c_files: HashMap<u64, String>,
pub parents: HashMap<CDeclId, CDeclId>,
pub comments: Vec<Located<String>>,
pub prenamed_decls: IndexMap<CDeclId, CDeclId>,
}
#[derive(Debug, Clone)]
pub struct CommentContext {
decl_comments: HashMap<CDeclId, Vec<String>>,
stmt_comments: HashMap<CStmtId, Vec<String>>,
}
impl TypedAstContext {
pub fn new() -> TypedAstContext {
TypedAstContext {
c_types: HashMap::new(),
c_exprs: HashMap::new(),
c_decls: IndexMap::new(),
c_stmts: HashMap::new(),
c_decls_top: Vec::new(),
c_main: None,
c_files: HashMap::new(),
parents: HashMap::new(),
comments: vec![],
prenamed_decls: IndexMap::new(),
}
}
pub fn is_null_expr(&self, expr_id: CExprId) -> bool {
match self[expr_id].kind {
CExprKind::ExplicitCast(_, _, CastKind::NullToPointer, _, _)
| CExprKind::ImplicitCast(_, _, CastKind::NullToPointer, _, _) => true,
CExprKind::ExplicitCast(ty, e, CastKind::BitCast, _, _)
| CExprKind::ImplicitCast(ty, e, CastKind::BitCast, _, _) => {
self.resolve_type(ty.ctype).kind.is_pointer() && self.is_null_expr(e)
}
_ => false,
}
}
pub fn is_forward_declared_type(&self, typ: CTypeId) -> bool {
match self.resolve_type(typ).kind.as_underlying_decl() {
Some(decl_id) => match self[decl_id].kind {
CDeclKind::Struct { fields: None, .. } => true,
CDeclKind::Union { fields: None, .. } => true,
CDeclKind::Enum {
integral_type: None,
..
} => true,
_ => false,
},
_ => false,
}
}
pub fn is_function_pointer(&self, typ: CTypeId) -> bool {
let resolved_ctype = self.resolve_type(typ);
if let CTypeKind::Pointer(p) = resolved_ctype.kind {
if let CTypeKind::Function { .. } = self.resolve_type(p.ctype).kind {
true
} else {
false
}
} else {
false
}
}
pub fn resolve_type_id(&self, typ: CTypeId) -> CTypeId {
match self.index(typ).kind {
CTypeKind::Attributed(ty, _) => self.resolve_type_id(ty.ctype),
CTypeKind::Elaborated(ty) => self.resolve_type_id(ty),
CTypeKind::Decayed(ty) => self.resolve_type_id(ty),
CTypeKind::TypeOf(ty) => self.resolve_type_id(ty),
CTypeKind::Paren(ty) => self.resolve_type_id(ty),
CTypeKind::Typedef(decl) => match self.index(decl).kind {
CDeclKind::Typedef { typ: ty, .. } => self.resolve_type_id(ty.ctype),
_ => panic!("Typedef decl did not point to a typedef"),
},
_ => typ,
}
}
pub fn resolve_type(&self, typ: CTypeId) -> &CType {
let resolved_typ_id = self.resolve_type_id(typ);
self.index(resolved_typ_id)
}
pub fn is_expr_pure(&self, expr: CExprId) -> bool {
match self.index(expr).kind {
CExprKind::BadExpr |
CExprKind::ShuffleVector(..) |
CExprKind::ConvertVector(..) |
CExprKind::Call(..) |
CExprKind::Unary(_, UnOp::PreIncrement, _, _) |
CExprKind::Unary(_, UnOp::PostIncrement, _, _) |
CExprKind::Unary(_, UnOp::PreDecrement, _, _) |
CExprKind::Unary(_, UnOp::PostDecrement, _, _) |
CExprKind::Binary(_, BinOp::Assign, _, _, _, _) |
CExprKind::InitList { .. } |
CExprKind::ImplicitValueInit { .. } |
CExprKind::Predefined(..) |
CExprKind::Statements(..) |
CExprKind::VAArg(..) => false,
CExprKind::Literal(_, _) |
CExprKind::DeclRef(_, _, _) |
CExprKind::UnaryType(_, _, _, _) |
CExprKind::OffsetOf(..) => true,
CExprKind::DesignatedInitExpr(_,_,e) |
CExprKind::ImplicitCast(_, e, _, _, _) |
CExprKind::ExplicitCast(_, e, _, _, _) |
CExprKind::Member(_, e, _, _, _) |
CExprKind::CompoundLiteral(_, e) |
CExprKind::Unary(_, _, e, _) => self.is_expr_pure(e),
CExprKind::Binary(_, op, _, _, _, _) if op.underlying_assignment().is_some() => false,
CExprKind::Binary(_, _, lhs, rhs, _, _) => self.is_expr_pure(lhs) && self.is_expr_pure(rhs),
CExprKind::ArraySubscript(_, lhs, rhs, _) => self.is_expr_pure(lhs) && self.is_expr_pure(rhs),
CExprKind::Conditional(_, c, lhs, rhs) => self.is_expr_pure(c) && self.is_expr_pure(lhs) && self.is_expr_pure(rhs),
CExprKind::BinaryConditional(_, lhs, rhs) => self.is_expr_pure(lhs) && self.is_expr_pure(rhs),
}
}
pub fn expr_diverges(&self, expr_id: CExprId) -> bool {
let func_id = match self.index(expr_id).kind {
CExprKind::Call(_, func_id, _) => func_id,
_ => return false,
};
let type_id = match self[func_id].kind.get_type() {
None => return false,
Some(t) => t,
};
let pointed_id = match self.index(type_id).kind {
CTypeKind::Pointer(pointer_qualtype) => pointer_qualtype.ctype,
_ => return false,
};
match self.index(pointed_id).kind {
CTypeKind::Function(_, _, _, no_return, _) => no_return,
_ => false,
}
}
pub fn prune_unused_decls(&mut self) {
use self::iterators::{DFNodes, SomeId};
let mut to_walk: Vec<CDeclId> = Vec::new();
let mut used: HashSet<CDeclId> = HashSet::new();
for &decl_id in &self.c_decls_top {
let decl = self.index(decl_id);
match decl.kind {
CDeclKind::Function {
body: Some(_),
is_global: true,
is_inline: false,
..
} => {
to_walk.push(decl_id);
used.insert(decl_id);
}
CDeclKind::Variable {
is_defn: true,
is_externally_visible: true,
..
} => {
to_walk.push(decl_id);
used.insert(decl_id);
}
CDeclKind::Variable { ref attrs, .. } | CDeclKind::Function { ref attrs, .. }
if attrs.contains(&Attribute::Used) =>
{
to_walk.push(decl_id);
used.insert(decl_id);
}
_ => {}
}
}
while let Some(enclosing_decl_id) = to_walk.pop() {
for some_id in DFNodes::new(self, SomeId::Decl(enclosing_decl_id)) {
match some_id {
SomeId::Type(type_id) => {
match self.c_types[&type_id].kind {
CTypeKind::Elaborated(decl_type_id) => {
let decl_id = self.c_types[&decl_type_id]
.kind
.as_decl_or_typedef()
.expect("target of CTypeKind::Elaborated isn't a decl?");
if used.insert(decl_id) {
to_walk.push(decl_id);
}
}
_ => {}
}
}
SomeId::Expr(expr_id) => match self.c_exprs[&expr_id].kind {
CExprKind::DeclRef(_, decl_id, _) => {
if used.insert(decl_id) {
to_walk.push(decl_id);
}
}
_ => {}
},
SomeId::Decl(decl_id) => {
if used.insert(decl_id) {
to_walk.push(decl_id);
}
match self.c_decls[&decl_id].kind {
CDeclKind::EnumConstant { .. } => {
let parent_id = self.parents[&decl_id];
if used.insert(parent_id) {
to_walk.push(parent_id);
}
}
_ => {}
}
}
SomeId::Stmt(_) => {}
}
}
}
if let Some(main_id) = self.c_main {
if !used.contains(&main_id) {
self.c_main = None;
}
}
self.c_decls
.retain(|&decl_id, _decl| used.contains(&decl_id));
self.c_decls_top.retain(|x| used.contains(x));
}
}
impl CommentContext {
pub fn empty() -> CommentContext {
CommentContext {
decl_comments: HashMap::new(),
stmt_comments: HashMap::new(),
}
}
pub fn new(ast_context: &mut TypedAstContext) -> CommentContext {
let mut decls: HashMap<u64, Vec<(SrcLoc, CDeclId)>> = HashMap::new();
for (decl_id, ref loc_decl) in &ast_context.c_decls {
if let Some(ref loc) = loc_decl.loc {
decls
.entry(loc.fileid)
.or_insert(vec![])
.push((loc.clone(), *decl_id));
}
}
decls.iter_mut().for_each(|(_, v)| v.sort());
let mut stmts: HashMap<u64, Vec<(SrcLoc, CStmtId)>> = HashMap::new();
for (stmt_id, ref loc_stmt) in &ast_context.c_stmts {
if let Some(ref loc) = loc_stmt.loc {
stmts
.entry(loc.fileid)
.or_insert(vec![])
.push((loc.clone(), *stmt_id));
}
}
stmts.iter_mut().for_each(|(_, v)| v.sort());
let mut decl_comments_map: HashMap<CDeclId, BTreeMap<SrcLoc, String>> = HashMap::new();
let mut stmt_comments_map: HashMap<CStmtId, BTreeMap<SrcLoc, String>> = HashMap::new();
let empty_vec1 = &vec![];
let empty_vec2 = &vec![];
while let Some(Located { loc, kind: str }) = ast_context.comments.pop() {
if let Some(loc) = loc {
let this_file_decls = decls.get(&loc.fileid).unwrap_or(empty_vec1);
let this_file_stmts = stmts.get(&loc.fileid).unwrap_or(empty_vec2);
let decl_ix = this_file_decls
.binary_search_by_key(&loc.line, |&(ref l, _)| l.line)
.unwrap_or_else(|x| x);
let stmt_ix = this_file_stmts
.binary_search_by_key(&loc.line, |&(ref l, _)| l.line)
.unwrap_or_else(|x| x);
match (this_file_decls.get(decl_ix), this_file_stmts.get(stmt_ix)) {
(Some(&(ref l1, d)), Some(&(ref l2, s))) => {
if l1 > l2 {
stmt_comments_map
.entry(s)
.or_insert(BTreeMap::new())
.insert(loc, str);
} else {
decl_comments_map
.entry(d)
.or_insert(BTreeMap::new())
.insert(loc, str);
}
}
(Some(&(_, d)), None) => {
decl_comments_map
.entry(d)
.or_insert(BTreeMap::new())
.insert(loc, str);
}
(None, Some(&(_, s))) => {
stmt_comments_map
.entry(s)
.or_insert(BTreeMap::new())
.insert(loc, str);
}
(None, None) => {
diag!(
Diagnostic::Comments,
"Didn't find a target node for the comment '{}'",
str
);
}
};
}
}
let decl_comments = decl_comments_map
.into_iter()
.map(|(decl_id, map)| (decl_id, map.into_iter().map(|(_, v)| v).collect()))
.collect();
let stmt_comments = stmt_comments_map
.into_iter()
.map(|(decl_id, map)| (decl_id, map.into_iter().map(|(_, v)| v).collect()))
.collect();
CommentContext {
decl_comments,
stmt_comments,
}
}
pub fn remove_decl_comment(&mut self, decl_id: CDeclId) -> Vec<String> {
self.decl_comments.remove(&decl_id).unwrap_or(vec![])
}
pub fn remove_stmt_comment(&mut self, stmt_id: CStmtId) -> Vec<String> {
self.stmt_comments.remove(&stmt_id).unwrap_or(vec![])
}
}
impl Index<CTypeId> for TypedAstContext {
type Output = CType;
fn index(&self, index: CTypeId) -> &CType {
match self.c_types.get(&index) {
None => panic!("Could not find {:?} in TypedAstContext", index),
Some(ty) => ty,
}
}
}
impl Index<CExprId> for TypedAstContext {
type Output = CExpr;
fn index(&self, index: CExprId) -> &CExpr {
static BADEXPR: CExpr = Located {
loc: None,
kind: CExprKind::BadExpr,
};
match self.c_exprs.get(&index) {
None => &BADEXPR,
Some(ty) => ty,
}
}
}
impl Index<CDeclId> for TypedAstContext {
type Output = CDecl;
fn index(&self, index: CDeclId) -> &CDecl {
match self.c_decls.get(&index) {
None => panic!("Could not find {:?} in TypedAstContext", index),
Some(ty) => ty,
}
}
}
impl Index<CStmtId> for TypedAstContext {
type Output = CStmt;
fn index(&self, index: CStmtId) -> &CStmt {
match self.c_stmts.get(&index) {
None => panic!("Could not find {:?} in TypedAstContext", index),
Some(ty) => ty,
}
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)]
pub struct SrcLoc {
pub fileid: u64,
pub line: u64,
pub column: u64,
pub file_path: Option<PathBuf>,
}
impl Display for SrcLoc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref file_path) = self.file_path {
write!(f, "{}:{}:{}", file_path.display(), self.line, self.column)
} else {
Debug::fmt(self, f)
}
}
}
#[derive(Debug, Clone)]
pub struct Located<T> {
pub loc: Option<SrcLoc>,
pub kind: T,
}
pub type CDecl = Located<CDeclKind>;
pub type CStmt = Located<CStmtKind>;
pub type CExpr = Located<CExprKind>;
pub type CType = Located<CTypeKind>;
#[derive(Debug, Clone)]
pub enum CDeclKind {
Function {
is_global: bool,
is_inline: bool,
is_implicit: bool,
is_extern: bool,
typ: CFuncTypeId,
name: String,
parameters: Vec<CParamId>,
body: Option<CStmtId>,
attrs: IndexSet<Attribute>,
},
Variable {
has_static_duration: bool,
has_thread_duration: bool,
is_externally_visible: bool,
is_defn: bool,
ident: String,
initializer: Option<CExprId>,
typ: CQualTypeId,
attrs: IndexSet<Attribute>,
},
Enum {
name: Option<String>,
variants: Vec<CEnumConstantId>,
integral_type: Option<CQualTypeId>,
},
EnumConstant {
name: String,
value: ConstIntExpr,
},
Typedef {
name: String,
typ: CQualTypeId,
is_implicit: bool,
},
Struct {
name: Option<String>,
fields: Option<Vec<CFieldId>>,
is_packed: bool,
manual_alignment: Option<u64>,
max_field_alignment: Option<u64>,
platform_byte_size: u64,
platform_alignment: u64,
},
Union {
name: Option<String>,
fields: Option<Vec<CFieldId>>,
},
Field {
name: String,
typ: CQualTypeId,
bitfield_width: Option<u64>,
platform_bit_offset: u64,
platform_type_bitwidth: u64,
},
}
impl CDeclKind {
pub fn get_name(&self) -> Option<&String> {
match self {
&CDeclKind::Function { name: ref i, .. } => Some(i),
&CDeclKind::Variable { ident: ref i, .. } => Some(i),
&CDeclKind::Typedef { name: ref i, .. } => Some(i),
&CDeclKind::EnumConstant { name: ref i, .. } => Some(i),
&CDeclKind::Enum {
name: Some(ref i), ..
} => Some(i),
&CDeclKind::Struct {
name: Some(ref i), ..
} => Some(i),
&CDeclKind::Union {
name: Some(ref i), ..
} => Some(i),
&CDeclKind::Field { name: ref i, .. } => Some(i),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub enum OffsetOfKind {
Constant(u64),
Variable(CQualTypeId, CDeclId, CExprId),
}
#[derive(Debug, Clone)]
pub enum CExprKind {
Literal(CQualTypeId, CLiteral),
Unary(CQualTypeId, UnOp, CExprId, LRValue),
UnaryType(CQualTypeId, UnTypeOp, Option<CExprId>, CQualTypeId),
OffsetOf(CQualTypeId, OffsetOfKind),
Binary(
CQualTypeId,
BinOp,
CExprId,
CExprId,
Option<CQualTypeId>,
Option<CQualTypeId>,
),
ImplicitCast(CQualTypeId, CExprId, CastKind, Option<CFieldId>, LRValue),
ExplicitCast(CQualTypeId, CExprId, CastKind, Option<CFieldId>, LRValue),
DeclRef(CQualTypeId, CDeclId, LRValue),
Call(CQualTypeId, CExprId, Vec<CExprId>),
Member(CQualTypeId, CExprId, CDeclId, MemberKind, LRValue),
ArraySubscript(CQualTypeId, CExprId, CExprId, LRValue),
Conditional(CQualTypeId, CExprId, CExprId, CExprId),
BinaryConditional(CQualTypeId, CExprId, CExprId),
InitList(CQualTypeId, Vec<CExprId>, Option<CFieldId>, Option<CExprId>),
ImplicitValueInit(CQualTypeId),
CompoundLiteral(CQualTypeId, CExprId),
Predefined(CQualTypeId, CExprId),
Statements(CQualTypeId, CStmtId),
VAArg(CQualTypeId, CExprId),
ShuffleVector(CQualTypeId, Vec<CExprId>),
ConvertVector(CQualTypeId, Vec<CExprId>),
DesignatedInitExpr(CQualTypeId, Vec<Designator>, CExprId),
BadExpr,
}
#[derive(Copy, Debug, Clone)]
pub enum MemberKind {
Arrow,
Dot,
}
impl CExprKind {
pub fn lrvalue(&self) -> LRValue {
match *self {
CExprKind::Unary(_, _, _, lrvalue)
| CExprKind::DeclRef(_, _, lrvalue)
| CExprKind::ImplicitCast(_, _, _, _, lrvalue)
| CExprKind::ExplicitCast(_, _, _, _, lrvalue)
| CExprKind::Member(_, _, _, _, lrvalue)
| CExprKind::ArraySubscript(_, _, _, lrvalue) => lrvalue,
_ => LRValue::RValue,
}
}
pub fn get_qual_type(&self) -> Option<CQualTypeId> {
match *self {
CExprKind::BadExpr => None,
CExprKind::Literal(ty, _)
| CExprKind::OffsetOf(ty, _)
| CExprKind::Unary(ty, _, _, _)
| CExprKind::UnaryType(ty, _, _, _)
| CExprKind::Binary(ty, _, _, _, _, _)
| CExprKind::ImplicitCast(ty, _, _, _, _)
| CExprKind::ExplicitCast(ty, _, _, _, _)
| CExprKind::DeclRef(ty, _, _)
| CExprKind::Call(ty, _, _)
| CExprKind::Member(ty, _, _, _, _)
| CExprKind::ArraySubscript(ty, _, _, _)
| CExprKind::Conditional(ty, _, _, _)
| CExprKind::BinaryConditional(ty, _, _)
| CExprKind::InitList(ty, _, _, _)
| CExprKind::ImplicitValueInit(ty)
| CExprKind::CompoundLiteral(ty, _)
| CExprKind::Predefined(ty, _)
| CExprKind::Statements(ty, _)
| CExprKind::VAArg(ty, _)
| CExprKind::ShuffleVector(ty, _)
| CExprKind::ConvertVector(ty, _)
| CExprKind::DesignatedInitExpr(ty, _, _) => Some(ty),
}
}
pub fn get_type(&self) -> Option<CTypeId> {
self.get_qual_type().map(|x| x.ctype)
}
pub fn get_bool(&self) -> Option<bool> {
match *self {
CExprKind::Literal(_, ref lit) => Some(lit.get_bool()),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CastKind {
BitCast,
LValueToRValue,
NoOp,
ToUnion,
ArrayToPointerDecay,
FunctionToPointerDecay,
NullToPointer,
IntegralToPointer,
PointerToIntegral,
ToVoid,
IntegralCast,
IntegralToBoolean,
IntegralToFloating,
FloatingToIntegral,
FloatingToBoolean,
BooleanToSignedIntegral,
PointerToBoolean,
FloatingCast,
FloatingRealToComplex,
FloatingComplexToReal,
FloatingComplexCast,
FloatingComplexToIntegralComplex,
IntegralRealToComplex,
IntegralComplexToReal,
IntegralComplexToBoolean,
IntegralComplexCast,
IntegralComplexToFloatingComplex,
BuiltinFnToFnPtr,
ConstCast,
VectorSplat,
}
#[derive(Debug, Clone, Copy)]
pub enum UnOp {
AddressOf,
Deref,
Plus,
PostIncrement,
PreIncrement,
Negate,
PostDecrement,
PreDecrement,
Complement,
Not,
Real,
Imag,
Extension,
Coawait,
}
#[derive(Debug, Clone, Copy)]
pub enum UnTypeOp {
SizeOf,
AlignOf,
PreferredAlignOf,
}
impl UnOp {
pub fn is_prefix(&self) -> bool {
match *self {
UnOp::PostIncrement => false,
UnOp::PostDecrement => false,
_ => true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinOp {
Multiply,
Divide,
Modulus,
Add,
Subtract,
ShiftLeft,
ShiftRight,
Less,
Greater,
LessEqual,
GreaterEqual,
EqualEqual,
NotEqual,
BitAnd,
BitXor,
BitOr,
And,
Or,
AssignAdd,
AssignSubtract,
AssignMultiply,
AssignDivide,
AssignModulus,
AssignBitXor,
AssignShiftLeft,
AssignShiftRight,
AssignBitOr,
AssignBitAnd,
Assign,
Comma,
}
impl BinOp {
pub fn underlying_assignment(&self) -> Option<BinOp> {
match *self {
BinOp::AssignAdd => Some(BinOp::Add),
BinOp::AssignSubtract => Some(BinOp::Subtract),
BinOp::AssignMultiply => Some(BinOp::Multiply),
BinOp::AssignDivide => Some(BinOp::Divide),
BinOp::AssignModulus => Some(BinOp::Modulus),
BinOp::AssignBitXor => Some(BinOp::BitXor),
BinOp::AssignShiftLeft => Some(BinOp::ShiftLeft),
BinOp::AssignShiftRight => Some(BinOp::ShiftRight),
BinOp::AssignBitOr => Some(BinOp::BitOr),
BinOp::AssignBitAnd => Some(BinOp::BitAnd),
_ => None,
}
}
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum IntBase {
Dec,
Hex,
Oct,
}
#[derive(Debug, Clone)]
pub enum CLiteral {
Integer(u64, IntBase),
Character(u64),
Floating(f64, String),
String(Vec<u8>, u8),
}
impl CLiteral {
pub fn get_bool(&self) -> bool {
match *self {
CLiteral::Integer(x, _) => x != 0u64,
CLiteral::Character(x) => x != 0u64,
CLiteral::Floating(x, _) => x != 0f64,
_ => true,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ConstIntExpr {
U(u64),
I(i64),
}
#[derive(Debug, Clone)]
pub enum CStmtKind {
Label(CStmtId),
Case(CExprId, CStmtId, ConstIntExpr),
Default(CStmtId),
Compound(Vec<CStmtId>),
Expr(CExprId),
Empty,
If {
scrutinee: CExprId,
true_variant: CStmtId,
false_variant: Option<CStmtId>,
},
Switch {
scrutinee: CExprId,
body: CStmtId,
},
While {
condition: CExprId,
body: CStmtId,
},
DoWhile {
body: CStmtId,
condition: CExprId,
},
ForLoop {
init: Option<CStmtId>,
condition: Option<CExprId>,
increment: Option<CExprId>,
body: CStmtId,
},
Goto(CLabelId),
Break,
Continue,
Return(Option<CExprId>),
Decls(Vec<CDeclId>),
Asm {
asm: String,
inputs: Vec<AsmOperand>,
outputs: Vec<AsmOperand>,
clobbers: Vec<String>,
is_volatile: bool,
},
}
#[derive(Clone, Debug)]
pub struct AsmOperand {
pub constraints: String,
pub expression: CExprId,
}
#[derive(Debug, Copy, Clone, Default, PartialEq)]
pub struct Qualifiers {
pub is_const: bool,
pub is_restrict: bool,
pub is_volatile: bool,
}
impl Qualifiers {
pub fn and(self, other: Qualifiers) -> Qualifiers {
Qualifiers {
is_const: self.is_const || other.is_const,
is_restrict: self.is_restrict || other.is_restrict,
is_volatile: self.is_volatile || other.is_volatile,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CQualTypeId {
pub qualifiers: Qualifiers,
pub ctype: CTypeId,
}
#[derive(Debug, Clone, PartialEq)]
pub enum CTypeKind {
Void,
Bool,
Char,
SChar,
Short,
Int,
Long,
LongLong,
UChar,
UShort,
UInt,
ULong,
ULongLong,
Float,
Double,
LongDouble,
Int128,
UInt128,
Complex(CTypeId),
Pointer(CQualTypeId),
ConstantArray(CTypeId, usize),
IncompleteArray(CTypeId),
VariableArray(CTypeId, Option<CExprId>),
TypeOf(CTypeId),
TypeOfExpr(CExprId),
Function(CQualTypeId, Vec<CQualTypeId>, bool, bool, bool),
Typedef(CTypedefId),
Decayed(CTypeId),
Elaborated(CTypeId),
Paren(CTypeId),
Struct(CRecordId),
Union(CRecordId),
Enum(CEnumId),
BuiltinFn,
Attributed(CQualTypeId, Option<Attribute>),
BlockPointer(CQualTypeId),
Vector(CQualTypeId, usize),
Half,
}
#[derive(Copy, Clone, Debug)]
pub enum Designator {
Index(u64),
Range(u64, u64),
Field(CFieldId),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Attribute {
Alias(String),
AlwaysInline,
Cold,
GnuInline,
NoInline,
NoReturn,
NotNull,
Nullable,
Section(String),
Used,
}
impl CTypeKind {
pub fn is_pointer(&self) -> bool {
match *self {
CTypeKind::Pointer { .. } => true,
_ => false,
}
}
pub fn is_bool(&self) -> bool {
match *self {
CTypeKind::Bool => true,
_ => false,
}
}
pub fn is_enum(&self) -> bool {
match *self {
CTypeKind::Enum { .. } => true,
_ => false,
}
}
pub fn is_integral_type(&self) -> bool {
self.is_unsigned_integral_type() || self.is_signed_integral_type()
}
pub fn is_unsigned_integral_type(&self) -> bool {
match *self {
CTypeKind::Bool => true,
CTypeKind::UChar => true,
CTypeKind::UInt => true,
CTypeKind::UShort => true,
CTypeKind::ULong => true,
CTypeKind::ULongLong => true,
CTypeKind::UInt128 => true,
_ => false,
}
}
pub fn is_signed_integral_type(&self) -> bool {
match *self {
CTypeKind::Char => true,
CTypeKind::SChar => true,
CTypeKind::Int => true,
CTypeKind::Short => true,
CTypeKind::Long => true,
CTypeKind::LongLong => true,
CTypeKind::Int128 => true,
_ => false,
}
}
pub fn is_floating_type(&self) -> bool {
match *self {
CTypeKind::Float => true,
CTypeKind::Double => true,
CTypeKind::LongDouble => true,
_ => false,
}
}
pub fn as_underlying_decl(&self) -> Option<CDeclId> {
match *self {
CTypeKind::Struct(decl_id) | CTypeKind::Union(decl_id) | CTypeKind::Enum(decl_id) => {
Some(decl_id)
}
_ => None,
}
}
pub fn as_decl_or_typedef(&self) -> Option<CDeclId> {
match *self {
CTypeKind::Typedef(decl_id)
| CTypeKind::Struct(decl_id)
| CTypeKind::Union(decl_id)
| CTypeKind::Enum(decl_id) => Some(decl_id),
_ => None,
}
}
pub fn is_vector(&self) -> bool {
match *self {
CTypeKind::Vector { .. } => true,
_ => false,
}
}
}