use c2rust_ast_exporter::clang_ast::*;
use c_ast::*;
use serde_cbor::Value;
use std::collections::HashMap;
use std::vec::Vec;
pub type NodeType = u16;
mod node_types {
pub const FUNC_TYPE: super::NodeType = 0b000000000001;
pub const OTHER_TYPE: super::NodeType = 0b000000000010;
pub const TYPE: super::NodeType = FUNC_TYPE | OTHER_TYPE;
pub const EXPR: super::NodeType = 0b000000000100;
pub const FIELD_DECL: super::NodeType = 0b000000001000;
pub const VAR_DECL: super::NodeType = 0b000000010000;
pub const RECORD_DECL: super::NodeType = 0b000000100000;
pub const TYPDEF_DECL: super::NodeType = 0b000001000000;
pub const ENUM_DECL: super::NodeType = 0b000010000000;
pub const ENUM_CON: super::NodeType = 0b000100000000;
pub const OTHER_DECL: super::NodeType = 0b001000000000;
pub const DECL: super::NodeType =
FIELD_DECL | VAR_DECL | RECORD_DECL | TYPDEF_DECL | ENUM_DECL | ENUM_CON | OTHER_DECL;
pub const LABEL_STMT: super::NodeType = 0b010000000000;
pub const OTHER_STMT: super::NodeType = 0b100000000000;
pub const STMT: super::NodeType = LABEL_STMT | OTHER_STMT;
}
type ClangId = u64;
type ImporterId = u64;
#[derive(Debug)]
pub struct IdMapper {
new_id_source: ImporterId,
old_to_new: HashMap<ClangId, ImporterId>,
new_to_old: HashMap<ImporterId, ClangId>,
}
impl IdMapper {
pub fn new() -> IdMapper {
IdMapper {
new_id_source: 0,
old_to_new: HashMap::new(),
new_to_old: HashMap::new(),
}
}
fn fresh_id(&mut self) -> ImporterId {
self.new_id_source += 1;
self.new_id_source
}
pub fn get_new(&mut self, old_id: ClangId) -> Option<ImporterId> {
self.old_to_new.get(&old_id).map(|o| *o)
}
pub fn get_or_create_new(&mut self, old_id: ClangId) -> ImporterId {
match self.get_new(old_id) {
Some(new_id) => new_id,
None => {
let new_id = self.fresh_id();
let inserted = self.old_to_new.insert(old_id, new_id).is_some();
assert!(
!inserted,
"get_or_create_new: overwrote an old id at {}",
old_id
);
new_id
}
}
}
pub fn get_old(&mut self, new_id: ImporterId) -> Option<ClangId> {
self.new_to_old.get(&new_id).map(|n| *n)
}
pub fn merge_old(&mut self, old_id: ClangId, other_old_id: ClangId) -> Option<ImporterId> {
self.get_new(old_id).map(|new_id| {
let inserted = self.old_to_new.insert(other_old_id, new_id).is_some();
assert!(
!inserted,
"get_or_create_new: overwrote an old id at {}",
other_old_id
);
new_id
})
}
}
fn located<T>(node: &AstNode, t: T) -> Located<T> {
Located {
loc: Some(SrcLoc {
line: node.line,
column: node.column,
fileid: node.fileid,
file_path: node.file_path.clone(),
}),
kind: t,
}
}
fn not_located<T>(t: T) -> Located<T> {
Located { loc: None, kind: t }
}
fn parse_cast_kind(kind: &str) -> CastKind {
match kind {
"BitCast" => CastKind::BitCast,
"LValueToRValue" => CastKind::LValueToRValue,
"NoOp" => CastKind::NoOp,
"ToUnion" => CastKind::ToUnion,
"ArrayToPointerDecay" => CastKind::ArrayToPointerDecay,
"FunctionToPointerDecay" => CastKind::FunctionToPointerDecay,
"NullToPointer" => CastKind::NullToPointer,
"IntegralToPointer" => CastKind::IntegralToPointer,
"PointerToIntegral" => CastKind::PointerToIntegral,
"ToVoid" => CastKind::ToVoid,
"IntegralCast" => CastKind::IntegralCast,
"IntegralToBoolean" => CastKind::IntegralToBoolean,
"IntegralToFloating" => CastKind::IntegralToFloating,
"FloatingToIntegral" => CastKind::FloatingToIntegral,
"FloatingToBoolean" => CastKind::FloatingToBoolean,
"BooleanToSignedIntegral" => CastKind::BooleanToSignedIntegral,
"PointerToBoolean" => CastKind::PointerToBoolean,
"FloatingCast" => CastKind::FloatingCast,
"FloatingRealToComplex" => CastKind::FloatingRealToComplex,
"FloatingComplexToReal" => CastKind::FloatingComplexToReal,
"FloatingComplexCast" => CastKind::FloatingComplexCast,
"FloatingComplexToIntegralComplex" => CastKind::FloatingComplexToIntegralComplex,
"IntegralRealToComplex" => CastKind::IntegralRealToComplex,
"IntegralComplexToReal" => CastKind::IntegralComplexToReal,
"IntegralComplexToBoolean" => CastKind::IntegralComplexToBoolean,
"IntegralComplexCast" => CastKind::IntegralComplexCast,
"IntegralComplexToFloatingComplex" => CastKind::IntegralComplexToFloatingComplex,
"BuiltinFnToFnPtr" => CastKind::BuiltinFnToFnPtr,
"ConstCast" => CastKind::ConstCast,
"VectorSplat" => CastKind::VectorSplat,
k => panic!("Unsupported implicit cast: {}", k),
}
}
fn parse_attributes(attributes: &[Value]) -> IndexSet<Attribute> {
let mut attrs = IndexSet::new();
let mut expect_section_value = false;
let mut expect_alias_value = false;
for attr in attributes {
let attr_str = attr
.as_string()
.expect("Decl attributes should be strings")
.as_str();
match attr_str {
"alias" => expect_alias_value = true,
"always_inline" => {
attrs.insert(Attribute::AlwaysInline);
}
"cold" => {
attrs.insert(Attribute::Cold);
}
"gnu_inline" => {
attrs.insert(Attribute::GnuInline);
}
"noinline" => {
attrs.insert(Attribute::NoInline);
}
"used" => {
attrs.insert(Attribute::Used);
}
"section" => expect_section_value = true,
s if expect_section_value => {
attrs.insert(Attribute::Section(s.into()));
expect_section_value = false;
}
s if expect_alias_value => {
attrs.insert(Attribute::Alias(s.into()));
expect_alias_value = false;
}
_ => {}
}
}
attrs
}
pub struct ConversionContext {
pub id_mapper: IdMapper,
processed_nodes: HashMap<ImporterId, NodeType>,
visit_as: Vec<(ClangId, NodeType)>,
pub typed_context: TypedAstContext,
}
impl ConversionContext {
pub fn new(untyped_context: &AstContext) -> ConversionContext {
let mut visit_as: Vec<(ClangId, NodeType)> = Vec::new();
for top_node in untyped_context.top_nodes.iter().rev() {
if untyped_context.ast_nodes.contains_key(&top_node) {
visit_as.push((*top_node, node_types::DECL));
}
}
ConversionContext {
id_mapper: IdMapper::new(),
processed_nodes: HashMap::new(),
visit_as,
typed_context: TypedAstContext::new(),
}
}
fn visit_node_type(&mut self, node_id: ClangId, node_ty: NodeType) -> ImporterId {
let node_id = if node_ty & node_types::TYPE != 0 {
node_id & TypeNode::ID_MASK
} else {
node_id
};
self.visit_as.push((node_id, node_ty));
self.id_mapper.get_or_create_new(node_id)
}
fn visit_type(&mut self, node_id: ClangId) -> CTypeId {
CTypeId(self.visit_node_type(node_id, node_types::TYPE))
}
fn visit_qualified_type(&mut self, node_id: ClangId) -> CQualTypeId {
let qualifiers = Qualifiers {
is_const: node_id & TypeNode::CONST_MASK != 0,
is_restrict: node_id & TypeNode::RESTRICT_MASK != 0,
is_volatile: node_id & TypeNode::VOLATILE_MASK != 0,
};
let ctype = self.visit_type(node_id);
CQualTypeId { qualifiers, ctype }
}
fn visit_stmt(&mut self, node_id: ClangId) -> CStmtId {
CStmtId(self.visit_node_type(node_id, node_types::STMT))
}
fn visit_expr(&mut self, node_id: ClangId) -> CExprId {
CExprId(self.visit_node_type(node_id, node_types::EXPR))
}
fn visit_decl(&mut self, node_id: ClangId) -> CDeclId {
CDeclId(self.visit_node_type(node_id, node_types::DECL))
}
fn add_type(&mut self, id: ImporterId, typ: CType) -> () {
self.typed_context.c_types.insert(CTypeId(id), typ);
}
fn add_stmt(&mut self, id: ImporterId, stmt: CStmt) -> () {
self.typed_context.c_stmts.insert(CStmtId(id), stmt);
}
fn add_expr(&mut self, id: ImporterId, expr: CExpr) -> () {
self.typed_context.c_exprs.insert(CExprId(id), expr);
}
fn add_decl(&mut self, id: ImporterId, decl: CDecl) -> () {
self.typed_context.c_decls.insert(CDeclId(id), decl);
}
fn expr_possibly_as_stmt(
&mut self,
expected_ty: NodeType,
new_id: ImporterId,
node: &AstNode,
expr: CExprKind,
) -> () {
if expected_ty & node_types::STMT != 0 {
let new_expr_id = self.id_mapper.fresh_id();
self.add_expr(new_expr_id, located(node, expr));
self.processed_nodes.insert(new_expr_id, node_types::EXPR);
let semi_stmt = CStmtKind::Expr(CExprId(new_expr_id));
self.add_stmt(new_id, located(node, semi_stmt));
self.processed_nodes.insert(new_id, node_types::STMT);
} else if expected_ty & node_types::EXPR != 0 {
self.add_expr(new_id, located(node, expr));
self.processed_nodes.insert(new_id, node_types::EXPR);
} else {
panic!("'expr_possibly_as_stmt' expects 'expected_ty' to be either 'EXPR' or 'STMT'");
}
}
pub fn convert(&mut self, untyped_context: &AstContext) -> () {
for raw_comment in &untyped_context.comments {
let comment = Located {
loc: Some(SrcLoc {
line: raw_comment.line,
column: raw_comment.column,
fileid: raw_comment.fileid,
file_path: None,
}),
kind: raw_comment.string.clone(),
};
self.typed_context.comments.push(comment);
}
while let Some((node_id, expected_ty)) = self.visit_as.pop() {
if let Some(ty) = self
.id_mapper
.get_new(node_id)
.and_then(|new_id| self.processed_nodes.get(&new_id))
{
if ty & expected_ty != 0 {
continue;
}
panic!(
"Expected {} to be a node of type {}, not {}",
&node_id, expected_ty, ty
);
}
let new_id = self.id_mapper.get_or_create_new(node_id);
if untyped_context.top_nodes.contains(&node_id) {
self.typed_context.c_decls_top.push(CDeclId(new_id));
}
self.visit_node(untyped_context, node_id, new_id, expected_ty)
}
}
fn visit_node(
&mut self,
untyped_context: &AstContext,
node_id: ClangId,
new_id: ImporterId,
expected_ty: NodeType,
) -> () {
use self::node_types::*;
if expected_ty & TYPE != 0 {
let ty_node: &TypeNode = match untyped_context.type_nodes.get(&node_id) {
Some(x) => x,
None => return,
};
match ty_node.tag {
TypeTag::TagBool if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Bool));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagVoid if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Void));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagChar if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Char));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagInt if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Int));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagShort if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Short));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagLong if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Long));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagLongLong if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::LongLong));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagUInt if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::UInt));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagUChar if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::UChar));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagSChar if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::SChar));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagUShort if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::UShort));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagULong if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::ULong));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagULongLong if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::ULongLong));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagDouble if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Double));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagLongDouble if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::LongDouble));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagFloat if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Float));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagHalf if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Half));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagInt128 if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::Int128));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagUInt128 if expected_ty & OTHER_TYPE != 0 => {
self.add_type(new_id, not_located(CTypeKind::UInt128));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagPointer if expected_ty & OTHER_TYPE != 0 => {
let pointed = ty_node.extras[0].as_u64().expect("Pointer child not found");
let pointed_new = self.visit_qualified_type(pointed);
let pointer_ty = CTypeKind::Pointer(pointed_new);
self.add_type(new_id, not_located(pointer_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagBlockPointer if expected_ty & OTHER_TYPE != 0 => {
let pointed = ty_node.extras[0]
.as_u64()
.expect("Block pointer child not found");
let pointed_new = self.visit_qualified_type(pointed);
let pointer_ty = CTypeKind::BlockPointer(pointed_new);
self.add_type(new_id, not_located(pointer_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagComplexType if expected_ty & OTHER_TYPE != 0 => {
let subelt = ty_node.extras[0].as_u64().expect("Complex child not found");
let subelt_new = self.visit_type(subelt);
let complex_ty = CTypeKind::Complex(subelt_new);
self.add_type(new_id, not_located(complex_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagStructType if expected_ty & OTHER_TYPE != 0 => {
let decl = ty_node.extras[0].as_u64().expect("Struct decl not found");
let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL));
let record_ty = CTypeKind::Struct(decl_new);
self.add_type(new_id, not_located(record_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagUnionType if expected_ty & OTHER_TYPE != 0 => {
let decl = ty_node.extras[0].as_u64().expect("Union decl not found");
let decl_new = CDeclId(self.visit_node_type(decl, RECORD_DECL));
let record_ty = CTypeKind::Union(decl_new);
self.add_type(new_id, not_located(record_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagFunctionType if expected_ty & FUNC_TYPE != 0 => {
let mut arguments: Vec<CQualTypeId> = ty_node.extras[0]
.as_array()
.expect("Function type expects array argument")
.iter()
.map(|cbor| {
let arg = cbor.as_u64().expect("Bad function type child id");
let arg_new = self.visit_qualified_type(arg);
arg_new
})
.collect();
let ret = arguments.remove(0);
let is_variadic = ty_node.extras[1]
.as_boolean()
.expect("Variadicity of function type not found");
let is_noreturn = ty_node.extras[2]
.as_boolean()
.expect("NoReturn of function type not found");
let has_proto = ty_node.extras[3]
.as_boolean()
.expect("HasProto of function type not found");
let function_ty =
CTypeKind::Function(ret, arguments, is_variadic, is_noreturn, has_proto);
self.add_type(new_id, not_located(function_ty));
self.processed_nodes.insert(new_id, FUNC_TYPE);
}
TypeTag::TagTypeOfType if expected_ty & TYPE != 0 => {
let type_of_old = ty_node.extras[0]
.as_u64()
.expect("Type of (type) child not found");
let type_of = self.visit_type(type_of_old);
let type_of_ty = CTypeKind::TypeOf(type_of);
self.add_type(new_id, not_located(type_of_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagTypedefType => {
let decl = ty_node.extras[0].as_u64().expect("Typedef decl not found");
let decl_new = CDeclId(self.visit_node_type(decl, TYPDEF_DECL));
let typedef_ty = CTypeKind::Typedef(decl_new);
self.add_type(new_id, not_located(typedef_ty));
self.processed_nodes.insert(new_id, expected_ty);
}
TypeTag::TagEnumType if expected_ty & OTHER_TYPE != 0 => {
let decl = ty_node.extras[0].as_u64().expect("Enum decl not found");
let decl_new = CDeclId(self.visit_node_type(decl, ENUM_DECL));
let enum_ty = CTypeKind::Enum(decl_new);
self.add_type(new_id, not_located(enum_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagDecayedType if expected_ty & OTHER_TYPE != 0 => {
let decayed_id = ty_node.extras[0]
.as_u64()
.expect("Decayed type child not found");
let decayed = self.visit_type(decayed_id);
let decayed_ty = CTypeKind::Decayed(decayed);
self.add_type(new_id, not_located(decayed_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagElaboratedType if expected_ty & OTHER_TYPE != 0 => {
let elaborated_id = ty_node.extras[0]
.as_u64()
.expect("Elaborated type child not found");
let elaborated = self.visit_type(elaborated_id);
let elaborated_ty = CTypeKind::Elaborated(elaborated);
self.add_type(new_id, not_located(elaborated_ty));
self.processed_nodes.insert(new_id, TYPE);
}
TypeTag::TagParenType => {
let paren_id = ty_node.extras[0]
.as_u64()
.expect("Paren type child not found");
let paren = self.visit_type(paren_id);
let paren_ty = CTypeKind::Paren(paren);
self.add_type(new_id, not_located(paren_ty));
self.processed_nodes.insert(new_id, TYPE);
}
TypeTag::TagAttributedType => {
let ty_id = ty_node.extras[0]
.as_u64()
.expect("Attributed type child not found");
let ty = self.visit_qualified_type(ty_id);
let kind = match expect_opt_str(&ty_node.extras[1])
.expect("Attributed type kind not found")
{
None => None,
Some("noreturn") => Some(Attribute::NoReturn),
Some("nullable") => Some(Attribute::Nullable),
Some("notnull") => Some(Attribute::NotNull),
Some(other) => panic!("Unknown type attribute: {}", other),
};
let ty = CTypeKind::Attributed(ty, kind);
self.add_type(new_id, not_located(ty));
self.processed_nodes.insert(new_id, TYPE);
}
TypeTag::TagConstantArrayType => {
let element_id = ty_node.extras[0].as_u64().expect("element id");
let element = self.visit_type(element_id);
let count = ty_node.extras[1].as_u64().expect("count");
let element_ty = CTypeKind::ConstantArray(element, count as usize);
self.add_type(new_id, not_located(element_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagIncompleteArrayType => {
let element_id = ty_node.extras[0].as_u64().expect("element id");
let element = self.visit_type(element_id);
let element_ty = CTypeKind::IncompleteArray(element);
self.add_type(new_id, not_located(element_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagVariableArrayType => {
let element_id = ty_node.extras[0].as_u64().expect("element id");
let element = self.visit_type(element_id);
let count_id = expect_opt_u64(&ty_node.extras[1]).expect("count id");
let count = count_id.map(|x| self.visit_expr(x));
let element_ty = CTypeKind::VariableArray(element, count);
self.add_type(new_id, not_located(element_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagBuiltinFn => {
let ty = CTypeKind::BuiltinFn;
self.add_type(new_id, not_located(ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
TypeTag::TagVectorType => {
let elt = ty_node.extras[0].as_u64().expect("Vector child not found");
let elt_new = self.visit_qualified_type(elt);
let count = ty_node.extras[1].as_u64().expect("count");
let vector_ty = CTypeKind::Vector(elt_new, count as usize);
self.add_type(new_id, not_located(vector_ty));
self.processed_nodes.insert(new_id, OTHER_TYPE);
}
t => panic!(
"Type conversion not implemented for {:?} expecting {:?}",
t, expected_ty
),
}
} else {
let node: &AstNode = match untyped_context.ast_nodes.get(&node_id) {
Some(x) => x,
None => return,
};
match node.tag {
ASTEntryTag::TagBreakStmt if expected_ty & OTHER_STMT != 0 => {
self.add_stmt(new_id, located(node, CStmtKind::Break));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagContinueStmt if expected_ty & OTHER_STMT != 0 => {
self.add_stmt(new_id, located(node, CStmtKind::Continue));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagCompoundStmt if expected_ty & OTHER_STMT != 0 => {
let constituent_stmts: Vec<CStmtId> = node
.children
.iter()
.map(|id| {
let arg_id = id.expect("Compound stmt child not found");
self.visit_stmt(arg_id)
})
.collect();
let compound_stmt = CStmtKind::Compound(constituent_stmts);
self.add_stmt(new_id, located(node, compound_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagDeclStmt if expected_ty & OTHER_STMT != 0 => {
let decls = node
.children
.iter()
.map(|decl| {
let decl_id = decl.expect("Decl not found in decl-statement");
self.visit_decl(decl_id)
})
.collect();
let decls_stmt = CStmtKind::Decls(decls);
self.add_stmt(new_id, located(node, decls_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagReturnStmt if expected_ty & OTHER_STMT != 0 => {
let return_expr_opt = node.children[0].map(|id| self.visit_expr(id));
let return_stmt = CStmtKind::Return(return_expr_opt);
self.add_stmt(new_id, located(node, return_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagIfStmt if expected_ty & OTHER_STMT != 0 => {
let scrutinee_old =
node.children[0].expect("If condition expression not found");
let scrutinee = self.visit_expr(scrutinee_old);
let true_variant_old =
node.children[1].expect("If then body statement not found");
let true_variant = self.visit_stmt(true_variant_old);
let false_variant = node.children[2].map(|id| self.visit_stmt(id));
let if_stmt = CStmtKind::If {
scrutinee,
true_variant,
false_variant,
};
self.add_stmt(new_id, located(node, if_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagGotoStmt if expected_ty & OTHER_STMT != 0 => {
let target_label_old = node.children[0].expect("Goto target label not found");
let target_label = CStmtId(self.visit_node_type(target_label_old, LABEL_STMT));
let goto_stmt = CStmtKind::Goto(target_label);
self.add_stmt(new_id, located(node, goto_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagNullStmt if expected_ty & OTHER_STMT != 0 => {
let null_stmt = CStmtKind::Empty;
self.add_stmt(new_id, located(node, null_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagForStmt if expected_ty & OTHER_STMT != 0 => {
let init = node.children[0].map(|id| self.visit_stmt(id));
let condition = node.children[1].map(|id| self.visit_expr(id));
let increment = node.children[2].map(|id| self.visit_expr(id));
let body_old = node.children[3].expect("For loop body not found");
let body = self.visit_stmt(body_old);
let for_stmt = CStmtKind::ForLoop {
init,
condition,
increment,
body,
};
self.add_stmt(new_id, located(node, for_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagWhileStmt if expected_ty & OTHER_STMT != 0 => {
let condition_old = node.children[0].expect("While loop condition not found");
let condition = self.visit_expr(condition_old);
let body_old = node.children[1].expect("While loop body not found");
let body = self.visit_stmt(body_old);
let while_stmt = CStmtKind::While { condition, body };
self.add_stmt(new_id, located(node, while_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagDoStmt if expected_ty & OTHER_STMT != 0 => {
let body_old = node.children[0].expect("Do loop body not found");
let body = self.visit_stmt(body_old);
let condition_old = node.children[1].expect("Do loop condition not found");
let condition = self.visit_expr(condition_old);
let do_stmt = CStmtKind::DoWhile { body, condition };
self.add_stmt(new_id, located(node, do_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagLabelStmt if expected_ty & LABEL_STMT != 0 => {
let substmt_old = node.children[0].expect("Label sub-statement not found");
let substmt = self.visit_stmt(substmt_old);
let label_stmt = CStmtKind::Label(substmt);
self.add_stmt(new_id, located(node, label_stmt));
self.processed_nodes.insert(new_id, LABEL_STMT);
}
ASTEntryTag::TagSwitchStmt if expected_ty & OTHER_STMT != 0 => {
let scrutinee_old = node.children[0].expect("Switch expression not found");
let scrutinee = self.visit_expr(scrutinee_old);
let body_old = node.children[1].expect("Switch body not found");
let body = self.visit_stmt(body_old);
let switch_stmt = CStmtKind::Switch { scrutinee, body };
self.add_stmt(new_id, located(node, switch_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagCaseStmt if expected_ty & OTHER_STMT != 0 => {
let expr_old = node.children[0].expect("Case expression not found");
let expr = self.visit_expr(expr_old);
let substmt_old = node.children[1].expect("Case sub-statement not found");
let substmt = self.visit_stmt(substmt_old);
let cie = match node.extras[0] {
Value::U64(n) => ConstIntExpr::U(n),
Value::I64(n) => ConstIntExpr::I(n),
_ => panic!("Expected constant int expr"),
};
let case_stmt = CStmtKind::Case(expr, substmt, cie);
self.add_stmt(new_id, located(node, case_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagDefaultStmt if expected_ty & OTHER_STMT != 0 => {
let substmt_old = node.children[0].expect("Default sub-statement not found");
let substmt = self.visit_stmt(substmt_old);
let default_stmt = CStmtKind::Default(substmt);
self.add_stmt(new_id, located(node, default_stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagAsmStmt if expected_ty & OTHER_STMT != 0 => {
let is_volatile = node.extras[0].as_boolean().expect("volatile flag");
let asm = node.extras[1]
.as_string()
.expect("assembly string")
.to_owned();
let raw_inputs = node.extras[2].as_array().expect("input constraints array");
let raw_outputs = node.extras[3].as_array().expect("output constraints array");
let raw_clobbers = node.extras[4].as_array().expect("clobber array");
let (input_children, output_children) =
node.children.split_at(raw_inputs.len());
let inputs: Vec<AsmOperand> = raw_inputs
.iter()
.zip(input_children)
.map(|(c, e)| {
let constraints = c.as_string().expect("constraint string").to_owned();
let expression = self.visit_expr(e.expect("expression"));
AsmOperand {
constraints,
expression,
}
})
.collect();
let outputs: Vec<AsmOperand> = raw_outputs
.iter()
.zip(output_children)
.map(|(c, e)| {
let constraints = c.as_string().expect("constraint string").to_owned();
let expression = self.visit_expr(e.expect("expression"));
AsmOperand {
constraints,
expression,
}
})
.collect();
let clobbers: Vec<String> = raw_clobbers
.iter()
.map(|c| c.as_string().expect("clobber string").to_owned())
.collect();
let stmt = CStmtKind::Asm {
is_volatile,
asm,
inputs,
outputs,
clobbers,
};
self.add_stmt(new_id, located(node, stmt));
self.processed_nodes.insert(new_id, OTHER_STMT);
}
ASTEntryTag::TagParenExpr if expected_ty & (EXPR | STMT) != 0 => {
let wrapped = node.children[0].expect("Expected wrapped paren expression");
self.id_mapper.merge_old(node_id, wrapped);
self.visit_node_type(wrapped, expected_ty);
}
ASTEntryTag::TagOffsetOfExpr if expected_ty & (EXPR | STMT) != 0 => {
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let offset_of = if let Some(value) = node.extras[0].as_u64() {
let kind = OffsetOfKind::Constant(value);
CExprKind::OffsetOf(ty, kind)
} else {
let qty_int = node.extras[1]
.as_u64()
.expect("Expected offset of to have struct type");
let qty = self.visit_qualified_type(qty_int);
let field = node.extras[2].as_u64().expect("Expected offset of field");
let field_id = self.visit_decl(field);
let index = node.extras[3]
.as_u64()
.expect("Expected offset of index expr");
let index_expr_id = self.visit_expr(index);
let kind = OffsetOfKind::Variable(qty, field_id, index_expr_id);
CExprKind::OffsetOf(ty, kind)
};
self.expr_possibly_as_stmt(expected_ty, new_id, node, offset_of);
}
ASTEntryTag::TagIntegerLiteral if expected_ty & (EXPR | STMT) != 0 => {
let value = node.extras[0]
.as_u64()
.expect("Expected integer literal value");
let base = node.extras[1]
.as_u64()
.expect("Expected integer base value");
let base = match base {
8 => IntBase::Oct,
10 => IntBase::Dec,
16 => IntBase::Hex,
_ => panic!("Invalid base: {}", base),
};
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let integer_literal = CExprKind::Literal(ty, CLiteral::Integer(value, base));
self.expr_possibly_as_stmt(expected_ty, new_id, node, integer_literal);
}
ASTEntryTag::TagStringLiteral if expected_ty & (EXPR | STMT) != 0 => {
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let width = node.extras[1].as_u64().expect("string literal char width") as u8;
let bytes = node.extras[2]
.as_bytes()
.expect("string literal bytes")
.to_owned();
let string_literal = CExprKind::Literal(ty, CLiteral::String(bytes, width));
self.expr_possibly_as_stmt(expected_ty, new_id, node, string_literal);
}
ASTEntryTag::TagCharacterLiteral if expected_ty & (EXPR | STMT) != 0 => {
let value = node.extras[0]
.as_u64()
.expect("Expected character literal value");
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let character_literal = CExprKind::Literal(ty, CLiteral::Character(value));
self.expr_possibly_as_stmt(expected_ty, new_id, node, character_literal);
}
ASTEntryTag::TagFloatingLiteral if expected_ty & (EXPR | STMT) != 0 => {
let value = node.extras[0]
.as_f64()
.expect("Expected float literal value");
let c_str = node.extras[1]
.as_string()
.expect("Expected float literal string")
.to_owned();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let floating_literal = CExprKind::Literal(ty, CLiteral::Floating(value, c_str));
self.expr_possibly_as_stmt(expected_ty, new_id, node, floating_literal);
}
ASTEntryTag::TagUnaryOperator if expected_ty & (EXPR | STMT) != 0 => {
let prefix = node.extras[1]
.as_boolean()
.expect("Expected prefix information");
let operator = match node.extras[0]
.as_string()
.expect("Expected operator")
.as_str()
{
"&" => UnOp::AddressOf,
"*" => UnOp::Deref,
"+" => UnOp::Plus,
"-" => UnOp::Negate,
"~" => UnOp::Complement,
"!" => UnOp::Not,
"++" => {
if prefix {
UnOp::PreIncrement
} else {
UnOp::PostIncrement
}
}
"--" => {
if prefix {
UnOp::PreDecrement
} else {
UnOp::PostDecrement
}
}
"__real" => UnOp::Real,
"__imag" => UnOp::Imag,
"__extension__" => UnOp::Extension,
"co_await" => UnOp::Coawait,
o => panic!("Unexpected operator: {}", o),
};
let operand_old = node.children[0].expect("Expected operand");
let operand = self.visit_expr(operand_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let unary = CExprKind::Unary(ty, operator, operand, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, unary);
}
ASTEntryTag::TagImplicitCastExpr if expected_ty & (EXPR | STMT) != 0 => {
let expression_old =
node.children[0].expect("Expected expression for implicit cast");
let expression = self.visit_expr(expression_old);
let typ_old = node.type_id.expect("Expected type for implicit cast");
let typ = self.visit_qualified_type(typ_old);
let kind =
parse_cast_kind(node.extras[0].as_string().expect("Expected cast kind"));
let implicit =
CExprKind::ImplicitCast(typ, expression, kind, None, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit);
}
ASTEntryTag::TagCStyleCastExpr if expected_ty & (EXPR | STMT) != 0 => {
let expression_old =
node.children[0].expect("Expected expression for explicit cast");
let expression = self.visit_expr(expression_old);
let typ_old = node.type_id.expect("Expected type for explicit cast");
let typ = self.visit_qualified_type(typ_old);
let kind =
parse_cast_kind(node.extras[0].as_string().expect("Expected cast kind"));
let opt_field_id = match kind {
CastKind::ToUnion => {
let id = node.children[1].expect("Expected field for union cast");
Some(self.visit_decl(id))
}
_ => None,
};
let implicit =
CExprKind::ExplicitCast(typ, expression, kind, opt_field_id, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, implicit);
}
ASTEntryTag::TagCallExpr if expected_ty & (EXPR | STMT) != 0 => {
let func_old = node.children[0].expect("Expected function for function call");
let func = self.visit_expr(func_old);
let args: Vec<CExprId> = node
.children
.iter()
.skip(1)
.map(|id| {
let arg_id = id.expect("Expected call expression argument");
self.visit_expr(arg_id)
})
.collect();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let call = CExprKind::Call(ty, func, args);
self.expr_possibly_as_stmt(expected_ty, new_id, node, call);
}
ASTEntryTag::TagMemberExpr if expected_ty & (EXPR | STMT) != 0 => {
let base_old = node.children[0].expect("Expected base for member expression");
let base = self.visit_expr(base_old);
let field_old = node.children[1].expect("Expected field for member expression");
let field = self.visit_decl(field_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let member_kind = if node.extras[0].as_boolean().expect("is arrow") {
MemberKind::Arrow
} else {
MemberKind::Dot
};
let member = CExprKind::Member(ty, base, field, member_kind, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, member);
}
ASTEntryTag::TagBinaryOperator if expected_ty & (EXPR | STMT) != 0 => {
let operator = match node.extras[0]
.as_string()
.expect("Expected operator")
.as_str()
{
"*" => BinOp::Multiply,
"/" => BinOp::Divide,
"%" => BinOp::Modulus,
"+" => BinOp::Add,
"-" => BinOp::Subtract,
"<<" => BinOp::ShiftLeft,
">>" => BinOp::ShiftRight,
"<" => BinOp::Less,
">" => BinOp::Greater,
"<=" => BinOp::LessEqual,
">=" => BinOp::GreaterEqual,
"==" => BinOp::EqualEqual,
"!=" => BinOp::NotEqual,
"&" => BinOp::BitAnd,
"^" => BinOp::BitXor,
"|" => BinOp::BitOr,
"&&" => BinOp::And,
"||" => BinOp::Or,
"+=" => BinOp::AssignAdd,
"-=" => BinOp::AssignSubtract,
"*=" => BinOp::AssignMultiply,
"/=" => BinOp::AssignDivide,
"%=" => BinOp::AssignModulus,
"^=" => BinOp::AssignBitXor,
"<<=" => BinOp::AssignShiftLeft,
">>=" => BinOp::AssignShiftRight,
"|=" => BinOp::AssignBitOr,
"&=" => BinOp::AssignBitAnd,
"=" => BinOp::Assign,
"," => BinOp::Comma,
_ => unimplemented!(),
};
let left_operand_old = node.children[0].expect("Expected left operand");
let left_operand = self.visit_expr(left_operand_old);
let right_operand_old = node.children[1].expect("Expected right operand");
let right_operand = self.visit_expr(right_operand_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let opt_lhs_type_id =
expect_opt_u64(&node.extras[1]).expect("Expected compute lhs type");
let opt_lhs_type = opt_lhs_type_id.map(|x| self.visit_qualified_type(x));
let opt_res_type_id =
expect_opt_u64(&node.extras[2]).expect("Expected compute lhs type");
let opt_res_type = opt_res_type_id.map(|x| self.visit_qualified_type(x));
let binary = CExprKind::Binary(
ty,
operator,
left_operand,
right_operand,
opt_lhs_type,
opt_res_type,
);
self.expr_possibly_as_stmt(expected_ty, new_id, node, binary);
}
ASTEntryTag::TagDeclRefExpr if expected_ty & (EXPR | STMT) != 0 => {
let declaration_old =
node.children[0].expect("Expected declaration on expression tag decl");
let declaration = self.visit_decl(declaration_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let decl = CExprKind::DeclRef(ty, declaration, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, decl);
}
ASTEntryTag::TagArraySubscriptExpr if expected_ty & (EXPR | STMT) != 0 => {
let lhs_old =
node.children[0].expect("Expected LHS on array subscript expression");
let lhs = self.visit_expr(lhs_old);
let rhs_old =
node.children[1].expect("Expected RHS on array subscript expression");
let rhs = self.visit_expr(rhs_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let subscript = CExprKind::ArraySubscript(ty, lhs, rhs, node.rvalue);
self.expr_possibly_as_stmt(expected_ty, new_id, node, subscript);
}
ASTEntryTag::TagConditionalOperator if expected_ty & (EXPR | STMT) != 0 => {
let cond_old = node.children[0].expect("Expected condition on if expression");
let cond = self.visit_expr(cond_old);
let lhs_old = node.children[1].expect("Expected 'then' on if expression");
let lhs = self.visit_expr(lhs_old);
let rhs_old = node.children[2].expect("Expected 'else' on if expression");
let rhs = self.visit_expr(rhs_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let conditional = CExprKind::Conditional(ty, cond, lhs, rhs);
self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional);
}
ASTEntryTag::TagBinaryConditionalOperator if expected_ty & (EXPR | STMT) != 0 => {
let lhs_old = node.children[0].expect("Expected condition on if expression");
let lhs = self.visit_expr(lhs_old);
let rhs_old = node.children[1].expect("Expected 'else' on if expression");
let rhs = self.visit_expr(rhs_old);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let conditional = CExprKind::BinaryConditional(ty, lhs, rhs);
self.expr_possibly_as_stmt(expected_ty, new_id, node, conditional);
}
ASTEntryTag::TagUnaryExprOrTypeTraitExpr if expected_ty & (EXPR | STMT) != 0 => {
let ty = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty);
let expr = node.children[0].map(|x| self.visit_expr(x));
let kind_name = node.extras[0].as_string().expect("expected kind").as_str();
let kind = match kind_name {
"sizeof" => UnTypeOp::SizeOf,
"alignof" => UnTypeOp::AlignOf,
"preferredalignof" => UnTypeOp::PreferredAlignOf,
str => panic!("Unsupported operation: {}", str),
};
let arg_ty = node.extras[1].as_u64().expect("expected type id");
let arg_ty = self.visit_qualified_type(arg_ty);
let operator = CExprKind::UnaryType(ty, kind, expr, arg_ty);
self.expr_possibly_as_stmt(expected_ty, new_id, node, operator);
}
ASTEntryTag::TagCompoundLiteralExpr => {
let ty_old = node
.type_id
.expect("Expected compound literal to have type");
let ty = self.visit_qualified_type(ty_old);
let val_old = node.children[0].expect("Expected child on compound literal");
let val = self.visit_expr(val_old);
self.expr_possibly_as_stmt(
expected_ty,
new_id,
node,
CExprKind::CompoundLiteral(ty, val),
)
}
ASTEntryTag::TagPredefinedExpr => {
let ty_old = node.type_id.expect("Expected predefined expr to have type");
let ty = self.visit_qualified_type(ty_old);
let val_old = node.children[0].expect("Expected child on predefined expr");
let val = self.visit_expr(val_old);
self.expr_possibly_as_stmt(
expected_ty,
new_id,
node,
CExprKind::Predefined(ty, val),
)
}
ASTEntryTag::TagImplicitValueInitExpr => {
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
self.expr_possibly_as_stmt(
expected_ty,
new_id,
node,
CExprKind::ImplicitValueInit(ty),
)
}
ASTEntryTag::TagInitListExpr => {
let exprs: Vec<CExprId> = node
.children
.iter()
.map(|id| {
let expr_id = id.expect("init expression id");
self.visit_expr(expr_id)
})
.collect();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let union_field_id = expect_opt_u64(&node.extras[0])
.expect("Bad union field ID entry")
.map(|x| self.visit_decl(x));
let syntax_id = expect_opt_u64(&node.extras[1])
.expect("Bad syntax ID entry")
.map(|x| self.visit_expr(x));
let kind = CExprKind::InitList(ty, exprs, union_field_id, syntax_id);
self.expr_possibly_as_stmt(expected_ty, new_id, node, kind)
}
ASTEntryTag::TagDesignatedInitExpr => {
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let designator_cbors = node.extras[0]
.as_array()
.expect("Expected designators array");
let designators = designator_cbors
.into_iter()
.map(|x| {
let entry = x.as_array().expect("expected designator array");
match entry[0].as_u64().expect("expected designator tag") {
1 => Designator::Index(
entry[1].as_u64().expect("expected array index"),
),
2 => Designator::Field(CDeclId(
entry[1].as_u64().expect("expected field id"),
)),
3 => Designator::Range(
entry[1].as_u64().expect("expected array start"),
entry[2].as_u64().expect("expected array end"),
),
n => panic!("invalid designator tag: {}", n),
}
})
.collect();
let init_id = node.children[0]
.expect("Expected initializer expression on designated init expr");
let init_expr = self.visit_expr(init_id);
let kind = CExprKind::DesignatedInitExpr(ty, designators, init_expr);
self.expr_possibly_as_stmt(expected_ty, new_id, node, kind)
}
ASTEntryTag::TagStmtExpr => {
let child_id = node.children[0].expect("Expected compound statement ID");
let child = self.visit_stmt(child_id);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let stmt_expr = CExprKind::Statements(ty, child);
self.expr_possibly_as_stmt(expected_ty, new_id, node, stmt_expr)
}
ASTEntryTag::TagVAArgExpr => {
let child_id = node.children[0].expect("Expected subexpression");
let child = self.visit_expr(child_id);
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let vaarg_expr = CExprKind::VAArg(ty, child);
self.expr_possibly_as_stmt(expected_ty, new_id, node, vaarg_expr)
}
ASTEntryTag::TagShuffleVectorExpr => {
let kids: Vec<CExprId> = node
.children
.iter()
.map(|id| {
let child_id = id.expect("Missing shuffle argument");
self.visit_expr(child_id)
})
.collect();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let e = CExprKind::ShuffleVector(ty, kids);
self.expr_possibly_as_stmt(expected_ty, new_id, node, e)
}
ASTEntryTag::TagConvertVectorExpr => {
let kids: Vec<CExprId> = node
.children
.iter()
.map(|id| {
let child_id = id.expect("Missing convert argument");
self.visit_expr(child_id)
})
.collect();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let e = CExprKind::ConvertVector(ty, kids);
self.expr_possibly_as_stmt(expected_ty, new_id, node, e)
}
ASTEntryTag::TagConstantExpr => {
let kids: Vec<CExprId> = node
.children
.iter()
.map(|id| {
let child_id = id.expect("Missing constant subexpr");
self.visit_expr(child_id)
})
.collect();
let ty_old = node.type_id.expect("Expected expression to have type");
let ty = self.visit_qualified_type(ty_old);
let e = CExprKind::ConvertVector(ty, kids);
self.expr_possibly_as_stmt(expected_ty, new_id, node, e)
}
ASTEntryTag::TagFunctionDecl if expected_ty & OTHER_DECL != 0 => {
let name = node.extras[0]
.as_string()
.expect("Expected to find function name")
.to_owned();
let is_global = node.extras[1]
.as_boolean()
.expect("Expected to find visibility");
let mut is_inline = node.extras[2]
.as_boolean()
.expect("Expected to find inline");
let is_main = node.extras[3].as_boolean().expect("Expected to find main");
if is_main {
self.typed_context.c_main = Some(CDeclId(new_id));
}
let is_implicit = node.extras[4]
.as_boolean()
.expect("Expected to find implicit");
let is_extern = node.extras[5]
.as_boolean()
.expect("Expected to find externness");
let attributes = node.extras[6]
.as_array()
.expect("Expected to find attributes");
let attrs = parse_attributes(attributes);
is_inline |= attrs.contains(&Attribute::AlwaysInline);
let typ_old = node
.type_id
.expect("Expected to find a type on a function decl");
let typ = CTypeId(self.visit_node_type(typ_old, TYPE));
let (body_id, parameter_ids) = node
.children
.split_last()
.expect("Expected to find a function body");
let body = body_id.map(|b| self.visit_stmt(b));
let parameters = parameter_ids
.iter()
.map(|id| {
let param = id.expect("Param field decl not found");
CDeclId(self.visit_node_type(param, VAR_DECL))
})
.collect();
let function_decl = CDeclKind::Function {
attrs,
body,
is_extern,
is_global,
is_implicit,
is_inline,
name,
parameters,
typ,
};
self.add_decl(new_id, located(node, function_decl));
self.processed_nodes.insert(new_id, OTHER_DECL);
}
ASTEntryTag::TagTypedefDecl if expected_ty & TYPDEF_DECL != 0 => {
let name = node.extras[0]
.as_string()
.expect("Expected to find typedef name")
.to_owned();
let is_implicit = node.extras[1]
.as_boolean()
.expect("Expected to find implicit");
let typ_old = node
.type_id
.expect("Expected to find type on typedef declaration");
let typ = self.visit_qualified_type(typ_old);
let typdef_decl = CDeclKind::Typedef {
name,
typ,
is_implicit,
};
self.add_decl(new_id, located(node, typdef_decl));
self.processed_nodes.insert(new_id, TYPDEF_DECL);
}
ASTEntryTag::TagEnumDecl if expected_ty & ENUM_DECL != 0 => {
let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string);
let variants = node
.children
.iter()
.map(|id| {
let con = id.expect("Enum constant not found");
let id = CDeclId(self.visit_node_type(con, ENUM_CON));
self.typed_context.parents.insert(id, CDeclId(new_id));
id
})
.collect();
let integral_type = node.type_id.map(|x| self.visit_qualified_type(x));
let enum_decl = CDeclKind::Enum {
name,
variants,
integral_type,
};
self.add_decl(new_id, located(node, enum_decl));
self.processed_nodes.insert(new_id, ENUM_DECL);
}
ASTEntryTag::TagEnumConstantDecl if expected_ty & ENUM_CON != 0 => {
let name = node.extras[0]
.as_string()
.expect("Expected to find enum constant name")
.to_owned();
let value = match node.extras[1] {
Value::U64(n) => ConstIntExpr::U(n),
Value::I64(n) => ConstIntExpr::I(n),
_ => panic!("Expected constant int expr"),
};
let enum_constant_decl = CDeclKind::EnumConstant { name, value };
self.add_decl(new_id, located(node, enum_constant_decl));
self.processed_nodes.insert(new_id, ENUM_CON);
}
ASTEntryTag::TagVarDecl if expected_ty & VAR_DECL != 0 => {
let ident = node.extras[0]
.as_string()
.expect("Expected to find variable name")
.to_owned();
let has_static_duration = node.extras[1]
.as_boolean()
.expect("Expected to find static duration");
let has_thread_duration = node.extras[2]
.as_boolean()
.expect("Expected to find thread duration");
let is_externally_visible = node.extras[3]
.as_boolean()
.expect("Expected to find visibility");
let is_defn = node.extras[4]
.as_boolean()
.expect("Expected to find whether decl is definition");
let attributes = node.extras[5]
.as_array()
.expect("Expected attribute array on var decl");
assert!(has_static_duration || has_thread_duration || !is_externally_visible,
format!("Variable cannot be extern without also being static or thread-local: {}", ident));
let initializer = node.children[0].map(|id| self.visit_expr(id));
let typ_id = node
.type_id
.expect("Expected to find type on variable declaration");
let typ = self.visit_qualified_type(typ_id);
let mut attrs = parse_attributes(attributes);
let variable_decl = CDeclKind::Variable {
has_static_duration,
has_thread_duration,
is_externally_visible,
is_defn,
ident,
initializer,
typ,
attrs,
};
self.add_decl(new_id, located(node, variable_decl));
self.processed_nodes.insert(new_id, VAR_DECL);
}
ASTEntryTag::TagStructDecl if expected_ty & RECORD_DECL != 0 => {
let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string);
let has_def = node.extras[1]
.as_boolean()
.expect("Expected has_def flag on struct");
let attrs = node.extras[2]
.as_array()
.expect("Expected attribute array on record");
let manual_alignment =
expect_opt_u64(&node.extras[3]).expect("Expected struct alignment");
let max_field_alignment =
expect_opt_u64(&node.extras[4]).expect("Expected struct field align");
let platform_byte_size = node.extras[5].as_u64().expect("Expected struct size");
let platform_alignment =
node.extras[6].as_u64().expect("Expected struct alignment");
let fields: Option<Vec<CDeclId>> = if has_def {
Some(
node.children
.iter()
.map(|id| {
let field = id.expect("Record field decl not found");
let id = CDeclId(self.visit_node_type(field, FIELD_DECL));
self.typed_context.parents.insert(id, CDeclId(new_id));
id
})
.collect(),
)
} else {
None
};
let mut is_packed = false;
for attr in attrs {
match attr
.as_string()
.expect("Records attributes should be strings")
.as_str()
{
"packed" => is_packed = true,
_ => {}
}
}
let record = CDeclKind::Struct {
name,
fields,
is_packed,
manual_alignment,
max_field_alignment,
platform_byte_size,
platform_alignment,
};
self.add_decl(new_id, located(node, record));
self.processed_nodes.insert(new_id, RECORD_DECL);
}
ASTEntryTag::TagUnionDecl if expected_ty & RECORD_DECL != 0 => {
let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string);
let has_def = node.extras[1]
.as_boolean()
.expect("Expected has_def flag on struct");
let fields: Option<Vec<CDeclId>> = if has_def {
Some(
node.children
.iter()
.map(|id| {
let field = id.expect("Record field decl not found");
let id = CDeclId(self.visit_node_type(field, FIELD_DECL));
self.typed_context.parents.insert(id, CDeclId(new_id));
id
})
.collect(),
)
} else {
None
};
let record = CDeclKind::Union { name, fields };
self.add_decl(new_id, located(node, record));
self.processed_nodes.insert(new_id, RECORD_DECL);
}
ASTEntryTag::TagFieldDecl if expected_ty & FIELD_DECL != 0 => {
let name = node.extras[0]
.as_string()
.expect("A field needs a name")
.to_owned();
let typ_id = node
.type_id
.expect("Expected to find type on field declaration");
let typ = self.visit_qualified_type(typ_id);
let bitfield_width = node.extras[1].as_u64();
let platform_bit_offset = node.extras[2]
.as_u64()
.expect("Did not find field bit offset");
let platform_type_bitwidth = node.extras[3]
.as_u64()
.expect("Did not find field bitwidth");
let field = CDeclKind::Field {
name,
typ,
bitfield_width,
platform_bit_offset,
platform_type_bitwidth,
};
self.add_decl(new_id, located(node, field));
self.processed_nodes.insert(new_id, FIELD_DECL);
}
t => panic!("Could not translate node {:?} as type {}", t, expected_ty),
}
}
}
}